1 /*****************************************************************************/
5 /* 6502 code generator */
9 /* (C) 1998-2009, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
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 /*****************************************************************************/
64 /*****************************************************************************/
66 /*****************************************************************************/
70 static void typeerror (unsigned type)
71 /* Print an error message about an invalid operand type */
73 /* Special handling for floats here: */
74 if ((type & CF_TYPE) == CF_FLOAT) {
75 Fatal ("Floating point type is currently unsupported");
77 Internal ("Invalid type in CF flags: %04X, type = %u", type, type & CF_TYPE);
83 static void CheckLocalOffs (unsigned Offs)
84 /* Check the offset into the stack for 8bit range */
87 /* Too many local vars */
88 Error ("Too many local variables");
94 static const char* GetLabelName (unsigned Flags, unsigned long Label, long Offs)
96 static char Buf [256]; /* Label name */
98 /* Create the correct label name */
99 switch (Flags & CF_ADDRMASK) {
102 /* Static memory cell */
104 xsprintf (Buf, sizeof (Buf), "%s%+ld", LocalLabelName (Label), Offs);
106 xsprintf (Buf, sizeof (Buf), "%s", LocalLabelName (Label));
113 xsprintf (Buf, sizeof (Buf), "_%s%+ld", (char*) Label, Offs);
115 xsprintf (Buf, sizeof (Buf), "_%s", (char*) Label);
120 /* Absolute address */
121 xsprintf (Buf, sizeof (Buf), "$%04X", (int)((Label+Offs) & 0xFFFF));
125 /* Variable in register bank */
126 xsprintf (Buf, sizeof (Buf), "regbank+%u", (unsigned)((Label+Offs) & 0xFFFF));
130 Internal ("Invalid address flags: %04X", Flags);
133 /* Return a pointer to the static buffer */
139 /*****************************************************************************/
140 /* Pre- and postamble */
141 /*****************************************************************************/
145 void g_preamble (void)
146 /* Generate the assembler code preamble */
148 /* Identify the compiler version */
150 AddTextLine ("; File generated by cc65 v %s", GetVersionAsString ());
153 /* Insert some object file options */
154 AddTextLine ("\t.fopt\t\tcompiler,\"cc65 v %s\"",
155 GetVersionAsString ());
157 /* If we're producing code for some other CPU, switch the command set */
159 case CPU_6502: AddTextLine ("\t.setcpu\t\t\"6502\""); break;
160 case CPU_6502X: AddTextLine ("\t.setcpu\t\t\"6502X\""); break;
161 case CPU_65SC02: AddTextLine ("\t.setcpu\t\t\"65SC02\""); break;
162 case CPU_65C02: AddTextLine ("\t.setcpu\t\t\"65C02\""); break;
163 case CPU_65816: AddTextLine ("\t.setcpu\t\t\"65816\""); break;
164 case CPU_HUC6280: AddTextLine ("\t.setcpu\t\t\"HUC6280\""); break;
165 default: Internal ("Unknown CPU: %d", CPU);
169 AddTextLine ("\t.smart\t\ton");
171 /* Allow auto import for runtime library routines */
172 AddTextLine ("\t.autoimport\ton");
174 /* Switch the assembler into case sensitive mode */
175 AddTextLine ("\t.case\t\ton");
177 /* Tell the assembler if we want to generate debug info */
178 AddTextLine ("\t.debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
180 /* Import the stack pointer for direct auto variable access */
181 AddTextLine ("\t.importzp\tsp, sreg, regsave, regbank, tmp1, ptr1, ptr2");
183 /* Define long branch macros */
184 AddTextLine ("\t.macpack\tlongbranch");
189 void g_fileinfo (const char* Name, unsigned long Size, unsigned long MTime)
190 /* If debug info is enabled, place a file info into the source */
193 /* We have to place this into the global text segment, so it will
194 * appear before all .dbg line statements.
196 TS_AddLine (GS->Text, "\t.dbg\t\tfile, \"%s\", %lu, %lu", Name, Size, MTime);
202 /*****************************************************************************/
203 /* Segment support */
204 /*****************************************************************************/
208 void g_userodata (void)
209 /* Switch to the read only data segment */
211 UseDataSeg (SEG_RODATA);
216 void g_usedata (void)
217 /* Switch to the data segment */
219 UseDataSeg (SEG_DATA);
225 /* Switch to the bss segment */
227 UseDataSeg (SEG_BSS);
232 void g_segname (segment_t Seg)
233 /* Emit the name of a segment if necessary */
235 /* Emit a segment directive for the data style segments */
238 case SEG_RODATA: S = CS->ROData; break;
239 case SEG_DATA: S = CS->Data; break;
240 case SEG_BSS: S = CS->BSS; break;
241 default: S = 0; break;
244 DS_AddLine (S, ".segment\t\"%s\"", GetSegName (Seg));
250 /*****************************************************************************/
252 /*****************************************************************************/
256 unsigned sizeofarg (unsigned flags)
257 /* Return the size of a function argument type that is encoded in flags */
259 switch (flags & CF_TYPE) {
262 return (flags & CF_FORCECHAR)? 1 : 2;
282 int pop (unsigned flags)
283 /* Pop an argument of the given size */
285 return StackPtr += sizeofarg (flags);
290 int push (unsigned flags)
291 /* Push an argument of the given size */
293 return StackPtr -= sizeofarg (flags);
298 static unsigned MakeByteOffs (unsigned Flags, unsigned Offs)
299 /* The value in Offs is an offset to an address in a/x. Make sure, an object
300 * of the type given in Flags can be loaded or stored into this address by
301 * adding part of the offset to the address in ax, so that the remaining
302 * offset fits into an index register. Return the remaining offset.
305 /* If the offset is too large for a byte register, add the high byte
306 * of the offset to the primary. Beware: We need a special correction
307 * if the offset in the low byte will overflow in the operation.
309 unsigned O = Offs & ~0xFFU;
310 if ((Offs & 0xFF) > 256 - sizeofarg (Flags)) {
311 /* We need to add the low byte also */
315 /* Do the correction if we need one */
317 g_inc (CF_INT | CF_CONST, O);
321 /* Return the new offset */
327 /*****************************************************************************/
328 /* Functions handling local labels */
329 /*****************************************************************************/
333 void g_defcodelabel (unsigned label)
334 /* Define a local code label */
336 CS_AddLabel (CS->Code, LocalLabelName (label));
341 void g_defdatalabel (unsigned label)
342 /* Define a local data label */
344 AddDataLine ("%s:", LocalLabelName (label));
349 void g_aliasdatalabel (unsigned label, unsigned baselabel, long offs)
350 /* Define label as a local alias for baselabel+offs */
352 /* We need an intermediate buffer here since LocalLabelName uses a
353 * static buffer which changes with each call.
355 StrBuf L = AUTO_STRBUF_INITIALIZER;
356 SB_AppendStr (&L, LocalLabelName (label));
358 AddDataLine ("%s\t:=\t%s+%ld",
360 LocalLabelName (baselabel),
367 /*****************************************************************************/
368 /* Functions handling global labels */
369 /*****************************************************************************/
373 void g_defgloblabel (const char* Name)
374 /* Define a global label with the given name */
376 /* Global labels are always data labels */
377 AddDataLine ("_%s:", Name);
382 void g_defexport (const char* Name, int ZP)
383 /* Export the given label */
386 AddTextLine ("\t.exportzp\t_%s", Name);
388 AddTextLine ("\t.export\t\t_%s", Name);
394 void g_defimport (const char* Name, int ZP)
395 /* Import the given label */
398 AddTextLine ("\t.importzp\t_%s", Name);
400 AddTextLine ("\t.import\t\t_%s", Name);
406 void g_importstartup (void)
407 /* Forced import of the startup module */
409 AddTextLine ("\t.forceimport\t__STARTUP__");
414 void g_importmainargs (void)
415 /* Forced import of a special symbol that handles arguments to main */
417 AddTextLine ("\t.forceimport\tinitmainargs");
422 /*****************************************************************************/
423 /* Function entry and exit */
424 /*****************************************************************************/
428 /* Remember the argument size of a function. The variable is set by g_enter
429 * and used by g_leave. If the functions gets its argument size by the caller
430 * (variable param list or function without prototype), g_enter will set the
436 void g_enter (unsigned flags, unsigned argsize)
437 /* Function prologue */
439 if ((flags & CF_FIXARGC) != 0) {
440 /* Just remember the argument size for the leave */
444 AddCodeLine ("jsr enter");
451 /* Function epilogue */
453 /* How many bytes of locals do we have to drop? */
454 unsigned ToDrop = (unsigned) -StackPtr;
456 /* If we didn't have a variable argument list, don't call leave */
459 /* Drop stackframe if needed */
460 g_drop (ToDrop + funcargs);
462 } else if (StackPtr != 0) {
464 /* We've a stack frame to drop */
466 g_drop (ToDrop); /* Inlines the code */
467 AddCodeLine ("jsr leave");
469 AddCodeLine ("ldy #$%02X", ToDrop);
470 AddCodeLine ("jsr leavey");
475 /* Nothing to drop */
476 AddCodeLine ("jsr leave");
480 /* Add the final rts */
486 /*****************************************************************************/
487 /* Register variables */
488 /*****************************************************************************/
492 void g_swap_regvars (int StackOffs, int RegOffs, unsigned Bytes)
493 /* Swap a register variable with a location on the stack */
495 /* Calculate the actual stack offset and check it */
496 StackOffs -= StackPtr;
497 CheckLocalOffs (StackOffs);
500 AddCodeLine ("ldy #$%02X", StackOffs & 0xFF);
503 if (IS_Get (&CodeSizeFactor) < 165) {
504 AddCodeLine ("ldx #$%02X", RegOffs & 0xFF);
505 AddCodeLine ("jsr regswap1");
507 AddCodeLine ("lda (sp),y");
508 AddCodeLine ("ldx regbank%+d", RegOffs);
509 AddCodeLine ("sta regbank%+d", RegOffs);
511 AddCodeLine ("sta (sp),y");
514 } else if (Bytes == 2) {
516 AddCodeLine ("ldx #$%02X", RegOffs & 0xFF);
517 AddCodeLine ("jsr regswap2");
521 AddCodeLine ("ldx #$%02X", RegOffs & 0xFF);
522 AddCodeLine ("lda #$%02X", Bytes & 0xFF);
523 AddCodeLine ("jsr regswap");
529 void g_save_regvars (int RegOffs, unsigned Bytes)
530 /* Save register variables */
532 /* Don't loop for up to two bytes */
535 AddCodeLine ("lda regbank%+d", RegOffs);
536 AddCodeLine ("jsr pusha");
538 } else if (Bytes == 2) {
540 AddCodeLine ("lda regbank%+d", RegOffs);
541 AddCodeLine ("ldx regbank%+d", RegOffs+1);
542 AddCodeLine ("jsr pushax");
546 /* More than two bytes - loop */
547 unsigned Label = GetLocalLabel ();
549 AddCodeLine ("ldy #$%02X", (unsigned char) (Bytes - 1));
550 AddCodeLine ("ldx #$%02X", (unsigned char) Bytes);
551 g_defcodelabel (Label);
552 AddCodeLine ("lda regbank%+d,x", RegOffs-1);
553 AddCodeLine ("sta (sp),y");
556 AddCodeLine ("bne %s", LocalLabelName (Label));
560 /* We pushed stuff, correct the stack pointer */
566 void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
567 /* Restore register variables */
569 /* Calculate the actual stack offset and check it */
570 StackOffs -= StackPtr;
571 CheckLocalOffs (StackOffs);
573 /* Don't loop for up to two bytes */
576 AddCodeLine ("ldy #$%02X", StackOffs);
577 AddCodeLine ("lda (sp),y");
578 AddCodeLine ("sta regbank%+d", RegOffs);
580 } else if (Bytes == 2) {
582 AddCodeLine ("ldy #$%02X", StackOffs);
583 AddCodeLine ("lda (sp),y");
584 AddCodeLine ("sta regbank%+d", RegOffs);
586 AddCodeLine ("lda (sp),y");
587 AddCodeLine ("sta regbank%+d", RegOffs+1);
589 } else if (Bytes == 3 && IS_Get (&CodeSizeFactor) >= 133) {
591 AddCodeLine ("ldy #$%02X", StackOffs);
592 AddCodeLine ("lda (sp),y");
593 AddCodeLine ("sta regbank%+d", RegOffs);
595 AddCodeLine ("lda (sp),y");
596 AddCodeLine ("sta regbank%+d", RegOffs+1);
598 AddCodeLine ("lda (sp),y");
599 AddCodeLine ("sta regbank%+d", RegOffs+2);
601 } else if (StackOffs <= RegOffs) {
603 /* More bytes, but the relation between the register offset in the
604 * register bank and the stack offset allows us to generate short
605 * code that uses just one index register.
607 unsigned Label = GetLocalLabel ();
608 AddCodeLine ("ldy #$%02X", StackOffs);
609 g_defcodelabel (Label);
610 AddCodeLine ("lda (sp),y");
611 AddCodeLine ("sta regbank%+d,y", RegOffs - StackOffs);
613 AddCodeLine ("cpy #$%02X", StackOffs + Bytes);
614 AddCodeLine ("bne %s", LocalLabelName (Label));
618 /* Ok, this is the generic code. We need to save X because the
619 * caller will only save A.
621 unsigned Label = GetLocalLabel ();
622 AddCodeLine ("stx tmp1");
623 AddCodeLine ("ldy #$%02X", (unsigned char) (StackOffs + Bytes - 1));
624 AddCodeLine ("ldx #$%02X", (unsigned char) (Bytes - 1));
625 g_defcodelabel (Label);
626 AddCodeLine ("lda (sp),y");
627 AddCodeLine ("sta regbank%+d,x", RegOffs);
630 AddCodeLine ("bpl %s", LocalLabelName (Label));
631 AddCodeLine ("ldx tmp1");
638 /*****************************************************************************/
639 /* Fetching memory cells */
640 /*****************************************************************************/
644 void g_getimmed (unsigned Flags, unsigned long Val, long Offs)
645 /* Load a constant into the primary register */
647 unsigned char B1, B2, B3, B4;
651 if ((Flags & CF_CONST) != 0) {
653 /* Numeric constant */
654 switch (Flags & CF_TYPE) {
657 if ((Flags & CF_FORCECHAR) != 0) {
658 AddCodeLine ("lda #$%02X", (unsigned char) Val);
663 AddCodeLine ("ldx #$%02X", (unsigned char) (Val >> 8));
664 AddCodeLine ("lda #$%02X", (unsigned char) Val);
668 /* Split the value into 4 bytes */
669 B1 = (unsigned char) (Val >> 0);
670 B2 = (unsigned char) (Val >> 8);
671 B3 = (unsigned char) (Val >> 16);
672 B4 = (unsigned char) (Val >> 24);
674 /* Remember which bytes are done */
678 AddCodeLine ("ldx #$%02X", B2);
681 AddCodeLine ("stx sreg");
685 AddCodeLine ("stx sreg+1");
688 if ((Done & 0x04) == 0 && B1 != B3) {
689 AddCodeLine ("lda #$%02X", B3);
690 AddCodeLine ("sta sreg");
693 if ((Done & 0x08) == 0 && B1 != B4) {
694 AddCodeLine ("lda #$%02X", B4);
695 AddCodeLine ("sta sreg+1");
698 AddCodeLine ("lda #$%02X", B1);
700 if ((Done & 0x04) == 0) {
702 AddCodeLine ("sta sreg");
704 if ((Done & 0x08) == 0) {
706 AddCodeLine ("sta sreg+1");
718 /* Some sort of label */
719 const char* Label = GetLabelName (Flags, Val, Offs);
721 /* Load the address into the primary */
722 AddCodeLine ("lda #<(%s)", Label);
723 AddCodeLine ("ldx #>(%s)", Label);
730 void g_getstatic (unsigned flags, unsigned long label, long offs)
731 /* Fetch an static memory cell into the primary register */
733 /* Create the correct label name */
734 const char* lbuf = GetLabelName (flags, label, offs);
736 /* Check the size and generate the correct load operation */
737 switch (flags & CF_TYPE) {
740 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
741 AddCodeLine ("lda %s", lbuf); /* load A from the label */
743 AddCodeLine ("ldx #$00");
744 AddCodeLine ("lda %s", lbuf); /* load A from the label */
745 if (!(flags & CF_UNSIGNED)) {
746 /* Must sign extend */
747 unsigned L = GetLocalLabel ();
748 AddCodeLine ("bpl %s", LocalLabelName (L));
756 AddCodeLine ("lda %s", lbuf);
757 if (flags & CF_TEST) {
758 AddCodeLine ("ora %s+1", lbuf);
760 AddCodeLine ("ldx %s+1", lbuf);
765 if (flags & CF_TEST) {
766 AddCodeLine ("lda %s+3", lbuf);
767 AddCodeLine ("ora %s+2", lbuf);
768 AddCodeLine ("ora %s+1", lbuf);
769 AddCodeLine ("ora %s+0", lbuf);
771 AddCodeLine ("lda %s+3", lbuf);
772 AddCodeLine ("sta sreg+1");
773 AddCodeLine ("lda %s+2", lbuf);
774 AddCodeLine ("sta sreg");
775 AddCodeLine ("ldx %s+1", lbuf);
776 AddCodeLine ("lda %s", lbuf);
788 void g_getlocal (unsigned Flags, int Offs)
789 /* Fetch specified local object (local var). */
792 switch (Flags & CF_TYPE) {
795 CheckLocalOffs (Offs);
796 if ((Flags & CF_FORCECHAR) || (Flags & CF_TEST)) {
797 AddCodeLine ("ldy #$%02X", Offs);
798 AddCodeLine ("lda (sp),y");
800 AddCodeLine ("ldy #$%02X", Offs);
801 AddCodeLine ("ldx #$00");
802 AddCodeLine ("lda (sp),y");
803 if ((Flags & CF_UNSIGNED) == 0) {
804 unsigned L = GetLocalLabel();
805 AddCodeLine ("bpl %s", LocalLabelName (L));
813 CheckLocalOffs (Offs + 1);
814 AddCodeLine ("ldy #$%02X", (unsigned char) (Offs+1));
815 if (Flags & CF_TEST) {
816 AddCodeLine ("lda (sp),y");
818 AddCodeLine ("ora (sp),y");
819 } else if (IS_Get (&CodeSizeFactor) < 165) {
820 AddCodeLine ("jsr ldaxysp");
822 AddCodeLine ("lda (sp),y");
825 AddCodeLine ("lda (sp),y");
830 CheckLocalOffs (Offs + 3);
831 AddCodeLine ("ldy #$%02X", (unsigned char) (Offs+3));
832 AddCodeLine ("jsr ldeaxysp");
833 if (Flags & CF_TEST) {
845 void g_getind (unsigned Flags, unsigned Offs)
846 /* Fetch the specified object type indirect through the primary register
847 * into the primary register
850 /* If the offset is greater than 255, add the part that is > 255 to
851 * the primary. This way we get an easy addition and use the low byte
854 Offs = MakeByteOffs (Flags, Offs);
856 /* Handle the indirect fetch */
857 switch (Flags & CF_TYPE) {
860 /* Character sized */
861 AddCodeLine ("ldy #$%02X", Offs);
862 if (Flags & CF_UNSIGNED) {
863 AddCodeLine ("jsr ldauidx");
865 AddCodeLine ("jsr ldaidx");
870 if (Flags & CF_TEST) {
871 AddCodeLine ("ldy #$%02X", Offs);
872 AddCodeLine ("sta ptr1");
873 AddCodeLine ("stx ptr1+1");
874 AddCodeLine ("lda (ptr1),y");
876 AddCodeLine ("ora (ptr1),y");
878 AddCodeLine ("ldy #$%02X", Offs+1);
879 AddCodeLine ("jsr ldaxidx");
884 AddCodeLine ("ldy #$%02X", Offs+3);
885 AddCodeLine ("jsr ldeaxidx");
886 if (Flags & CF_TEST) {
899 void g_leasp (int Offs)
900 /* Fetch the address of the specified symbol into the primary register */
902 unsigned char Lo, Hi;
904 /* Calculate the offset relative to sp */
907 /* Get low and high byte */
908 Lo = (unsigned char) Offs;
909 Hi = (unsigned char) (Offs >> 8);
914 AddCodeLine ("lda sp");
915 AddCodeLine ("ldx sp+1");
920 AddCodeLine ("lda sp+1");
922 AddCodeLine ("adc #$%02X", Hi);
924 AddCodeLine ("lda sp");
926 } else if (Hi == 0) {
928 if (IS_Get (&CodeSizeFactor) < 200) {
929 /* 8 bit offset with subroutine call */
930 AddCodeLine ("lda #$%02X", Lo);
931 AddCodeLine ("jsr leaa0sp");
933 /* 8 bit offset inlined */
934 unsigned L = GetLocalLabel ();
935 AddCodeLine ("lda sp");
936 AddCodeLine ("ldx sp+1");
938 AddCodeLine ("adc #$%02X", Lo);
939 AddCodeLine ("bcc %s", LocalLabelName (L));
943 } else if (IS_Get (&CodeSizeFactor) < 170) {
944 /* Full 16 bit offset with subroutine call */
945 AddCodeLine ("lda #$%02X", Lo);
946 AddCodeLine ("ldx #$%02X", Hi);
947 AddCodeLine ("jsr leaaxsp");
949 /* Full 16 bit offset inlined */
950 AddCodeLine ("lda sp");
952 AddCodeLine ("adc #$%02X", Lo);
954 AddCodeLine ("lda sp+1");
955 AddCodeLine ("adc #$%02X", Hi);
963 void g_leavariadic (int Offs)
964 /* Fetch the address of a parameter in a variadic function into the primary
968 unsigned ArgSizeOffs;
970 /* Calculate the offset relative to sp */
973 /* Get the offset of the parameter which is stored at sp+0 on function
974 * entry and check if this offset is reachable with a byte offset.
976 CHECK (StackPtr <= 0);
977 ArgSizeOffs = -StackPtr;
978 CheckLocalOffs (ArgSizeOffs);
980 /* Get the size of all parameters. */
981 AddCodeLine ("ldy #$%02X", ArgSizeOffs);
982 AddCodeLine ("lda (sp),y");
984 /* Add the value of the stackpointer */
985 if (IS_Get (&CodeSizeFactor) > 250) {
986 unsigned L = GetLocalLabel();
987 AddCodeLine ("ldx sp+1");
989 AddCodeLine ("adc sp");
990 AddCodeLine ("bcc %s", LocalLabelName (L));
994 AddCodeLine ("ldx #$00");
995 AddCodeLine ("jsr leaaxsp");
998 /* Add the offset to the primary */
1000 g_inc (CF_INT | CF_CONST, Offs);
1001 } else if (Offs < 0) {
1002 g_dec (CF_INT | CF_CONST, -Offs);
1008 /*****************************************************************************/
1009 /* Store into memory */
1010 /*****************************************************************************/
1014 void g_putstatic (unsigned flags, unsigned long label, long offs)
1015 /* Store the primary register into the specified static memory cell */
1017 /* Create the correct label name */
1018 const char* lbuf = GetLabelName (flags, label, offs);
1020 /* Check the size and generate the correct store operation */
1021 switch (flags & CF_TYPE) {
1024 AddCodeLine ("sta %s", lbuf);
1028 AddCodeLine ("sta %s", lbuf);
1029 AddCodeLine ("stx %s+1", lbuf);
1033 AddCodeLine ("sta %s", lbuf);
1034 AddCodeLine ("stx %s+1", lbuf);
1035 AddCodeLine ("ldy sreg");
1036 AddCodeLine ("sty %s+2", lbuf);
1037 AddCodeLine ("ldy sreg+1");
1038 AddCodeLine ("sty %s+3", lbuf);
1049 void g_putlocal (unsigned Flags, int Offs, long Val)
1050 /* Put data into local object. */
1053 CheckLocalOffs (Offs);
1054 switch (Flags & CF_TYPE) {
1057 if (Flags & CF_CONST) {
1058 AddCodeLine ("lda #$%02X", (unsigned char) Val);
1060 AddCodeLine ("ldy #$%02X", Offs);
1061 AddCodeLine ("sta (sp),y");
1065 if (Flags & CF_CONST) {
1066 AddCodeLine ("ldy #$%02X", Offs+1);
1067 AddCodeLine ("lda #$%02X", (unsigned char) (Val >> 8));
1068 AddCodeLine ("sta (sp),y");
1069 if ((Flags & CF_NOKEEP) == 0) {
1070 /* Place high byte into X */
1071 AddCodeLine ("tax");
1073 if ((Val & 0xFF) == Offs+1) {
1074 /* The value we need is already in Y */
1075 AddCodeLine ("tya");
1076 AddCodeLine ("dey");
1078 AddCodeLine ("dey");
1079 AddCodeLine ("lda #$%02X", (unsigned char) Val);
1081 AddCodeLine ("sta (sp),y");
1083 AddCodeLine ("ldy #$%02X", Offs);
1084 if ((Flags & CF_NOKEEP) == 0 || IS_Get (&CodeSizeFactor) < 160) {
1085 AddCodeLine ("jsr staxysp");
1087 AddCodeLine ("sta (sp),y");
1088 AddCodeLine ("iny");
1089 AddCodeLine ("txa");
1090 AddCodeLine ("sta (sp),y");
1096 if (Flags & CF_CONST) {
1097 g_getimmed (Flags, Val, 0);
1099 AddCodeLine ("ldy #$%02X", Offs);
1100 AddCodeLine ("jsr steaxysp");
1111 void g_putind (unsigned Flags, unsigned Offs)
1112 /* Store the specified object type in the primary register at the address
1113 * on the top of the stack
1116 /* We can handle offsets below $100 directly, larger offsets must be added
1117 * to the address. Since a/x is in use, best code is achieved by adding
1118 * just the high byte. Be sure to check if the low byte will overflow while
1121 if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
1123 /* Overflow - we need to add the low byte also */
1124 AddCodeLine ("ldy #$00");
1125 AddCodeLine ("clc");
1126 AddCodeLine ("pha");
1127 AddCodeLine ("lda #$%02X", Offs & 0xFF);
1128 AddCodeLine ("adc (sp),y");
1129 AddCodeLine ("sta (sp),y");
1130 AddCodeLine ("iny");
1131 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1132 AddCodeLine ("adc (sp),y");
1133 AddCodeLine ("sta (sp),y");
1134 AddCodeLine ("pla");
1136 /* Complete address is on stack, new offset is zero */
1139 } else if ((Offs & 0xFF00) != 0) {
1141 /* We can just add the high byte */
1142 AddCodeLine ("ldy #$01");
1143 AddCodeLine ("clc");
1144 AddCodeLine ("pha");
1145 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1146 AddCodeLine ("adc (sp),y");
1147 AddCodeLine ("sta (sp),y");
1148 AddCodeLine ("pla");
1150 /* Offset is now just the low byte */
1154 /* Check the size and determine operation */
1155 AddCodeLine ("ldy #$%02X", Offs);
1156 switch (Flags & CF_TYPE) {
1159 AddCodeLine ("jsr staspidx");
1163 AddCodeLine ("jsr staxspidx");
1167 AddCodeLine ("jsr steaxspidx");
1175 /* Pop the argument which is always a pointer */
1181 /*****************************************************************************/
1182 /* type conversion and similiar stuff */
1183 /*****************************************************************************/
1187 void g_toslong (unsigned flags)
1188 /* Make sure, the value on TOS is a long. Convert if necessary */
1190 switch (flags & CF_TYPE) {
1194 if (flags & CF_UNSIGNED) {
1195 AddCodeLine ("jsr tosulong");
1197 AddCodeLine ("jsr toslong");
1212 void g_tosint (unsigned flags)
1213 /* Make sure, the value on TOS is an int. Convert if necessary */
1215 switch (flags & CF_TYPE) {
1222 AddCodeLine ("jsr tosint");
1233 void g_regint (unsigned Flags)
1234 /* Make sure, the value in the primary register an int. Convert if necessary */
1238 switch (Flags & CF_TYPE) {
1241 if (Flags & CF_FORCECHAR) {
1242 /* Conversion is from char */
1243 if (Flags & CF_UNSIGNED) {
1244 AddCodeLine ("ldx #$00");
1246 L = GetLocalLabel();
1247 AddCodeLine ("ldx #$00");
1248 AddCodeLine ("cmp #$80");
1249 AddCodeLine ("bcc %s", LocalLabelName (L));
1250 AddCodeLine ("dex");
1267 void g_reglong (unsigned Flags)
1268 /* Make sure, the value in the primary register a long. Convert if necessary */
1272 switch (Flags & CF_TYPE) {
1275 if (Flags & CF_FORCECHAR) {
1276 /* Conversion is from char */
1277 if (Flags & CF_UNSIGNED) {
1278 if (IS_Get (&CodeSizeFactor) >= 200) {
1279 AddCodeLine ("ldx #$00");
1280 AddCodeLine ("stx sreg");
1281 AddCodeLine ("stx sreg+1");
1283 AddCodeLine ("jsr aulong");
1286 if (IS_Get (&CodeSizeFactor) >= 366) {
1287 L = GetLocalLabel();
1288 AddCodeLine ("ldx #$00");
1289 AddCodeLine ("cmp #$80");
1290 AddCodeLine ("bcc %s", LocalLabelName (L));
1291 AddCodeLine ("dex");
1293 AddCodeLine ("stx sreg");
1294 AddCodeLine ("stx sreg+1");
1296 AddCodeLine ("jsr along");
1303 if (Flags & CF_UNSIGNED) {
1304 if (IS_Get (&CodeSizeFactor) >= 200) {
1305 AddCodeLine ("ldy #$00");
1306 AddCodeLine ("sty sreg");
1307 AddCodeLine ("sty sreg+1");
1309 AddCodeLine ("jsr axulong");
1312 AddCodeLine ("jsr axlong");
1326 unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1327 /* Adjust the integer operands before doing a binary operation. lhs is a flags
1328 * value, that corresponds to the value on TOS, rhs corresponds to the value
1329 * in (e)ax. The return value is the the flags value for the resulting type.
1332 unsigned ltype, rtype;
1335 /* Get the type spec from the flags */
1336 ltype = lhs & CF_TYPE;
1337 rtype = rhs & CF_TYPE;
1339 /* Check if a conversion is needed */
1340 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1341 /* We must promote the primary register to long */
1343 /* Get the new rhs type */
1344 rhs = (rhs & ~CF_TYPE) | CF_LONG;
1346 } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1347 /* We must promote the lhs to long */
1353 /* Get the new rhs type */
1354 lhs = (lhs & ~CF_TYPE) | CF_LONG;
1358 /* Determine the result type for the operation:
1359 * - The result is const if both operands are const.
1360 * - The result is unsigned if one of the operands is unsigned.
1361 * - The result is long if one of the operands is long.
1362 * - Otherwise the result is int sized.
1364 result = (lhs & CF_CONST) & (rhs & CF_CONST);
1365 result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1366 if (rtype == CF_LONG || ltype == CF_LONG) {
1376 unsigned g_typecast (unsigned lhs, unsigned rhs)
1377 /* Cast the value in the primary register to the operand size that is flagged
1378 * by the lhs value. Return the result value.
1381 unsigned ltype, rtype;
1383 /* Get the type spec from the flags */
1384 ltype = lhs & CF_TYPE;
1385 rtype = rhs & CF_TYPE;
1387 /* Check if a conversion is needed */
1388 if ((rhs & CF_CONST) == 0) {
1389 if (ltype == CF_LONG && rtype != CF_LONG) {
1390 /* We must promote the primary register to long */
1392 } else if (ltype == CF_INT && rtype != CF_INT) {
1393 /* We must promote the primary register to int */
1398 /* Do not need any other action. If the left type is int, and the primary
1399 * register is long, it will be automagically truncated. If the right hand
1400 * side is const, it is not located in the primary register and handled by
1401 * the expression parser code.
1404 /* Result is const if the right hand side was const */
1405 lhs |= (rhs & CF_CONST);
1407 /* The resulting type is that of the left hand side (that's why you called
1415 void g_scale (unsigned flags, long val)
1416 /* Scale the value in the primary register by the given value. If val is positive,
1417 * scale up, is val is negative, scale down. This function is used to scale
1418 * the operands or results of pointer arithmetic by the size of the type, the
1419 * pointer points to.
1424 /* Value may not be zero */
1426 Internal ("Data type has no size");
1427 } else if (val > 0) {
1430 if ((p2 = PowerOf2 (val)) > 0 && p2 <= 4) {
1432 /* Factor is 2, 4, 8 and 16, use special function */
1433 switch (flags & CF_TYPE) {
1436 if (flags & CF_FORCECHAR) {
1438 AddCodeLine ("asl a");
1445 if (flags & CF_UNSIGNED) {
1446 AddCodeLine ("jsr shlax%d", p2);
1448 AddCodeLine ("jsr aslax%d", p2);
1453 if (flags & CF_UNSIGNED) {
1454 AddCodeLine ("jsr shleax%d", p2);
1456 AddCodeLine ("jsr asleax%d", p2);
1465 } else if (val != 1) {
1467 /* Use a multiplication instead */
1468 g_mul (flags | CF_CONST, val);
1476 if ((p2 = PowerOf2 (val)) > 0 && p2 <= 4) {
1478 /* Factor is 2, 4, 8 and 16 use special function */
1479 switch (flags & CF_TYPE) {
1482 if (flags & CF_FORCECHAR) {
1483 if (flags & CF_UNSIGNED) {
1485 AddCodeLine ("lsr a");
1488 } else if (p2 <= 2) {
1489 AddCodeLine ("cmp #$80");
1490 AddCodeLine ("ror a");
1497 if (flags & CF_UNSIGNED) {
1498 AddCodeLine ("jsr lsrax%d", p2);
1500 AddCodeLine ("jsr asrax%d", p2);
1505 if (flags & CF_UNSIGNED) {
1506 AddCodeLine ("jsr lsreax%d", p2);
1508 AddCodeLine ("jsr asreax%d", p2);
1517 } else if (val != 1) {
1519 /* Use a division instead */
1520 g_div (flags | CF_CONST, val);
1528 /*****************************************************************************/
1529 /* Adds and subs of variables fix a fixed address */
1530 /*****************************************************************************/
1534 void g_addlocal (unsigned flags, int offs)
1535 /* Add a local variable to ax */
1539 /* Correct the offset and check it */
1541 CheckLocalOffs (offs);
1543 switch (flags & CF_TYPE) {
1546 L = GetLocalLabel();
1547 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1548 AddCodeLine ("clc");
1549 AddCodeLine ("adc (sp),y");
1550 AddCodeLine ("bcc %s", LocalLabelName (L));
1551 AddCodeLine ("inx");
1556 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1557 AddCodeLine ("clc");
1558 AddCodeLine ("adc (sp),y");
1559 AddCodeLine ("pha");
1560 AddCodeLine ("txa");
1561 AddCodeLine ("iny");
1562 AddCodeLine ("adc (sp),y");
1563 AddCodeLine ("tax");
1564 AddCodeLine ("pla");
1568 /* Do it the old way */
1570 g_getlocal (flags, offs);
1582 void g_addstatic (unsigned flags, unsigned long label, long offs)
1583 /* Add a static variable to ax */
1587 /* Create the correct label name */
1588 const char* lbuf = GetLabelName (flags, label, offs);
1590 switch (flags & CF_TYPE) {
1593 L = GetLocalLabel();
1594 AddCodeLine ("clc");
1595 AddCodeLine ("adc %s", lbuf);
1596 AddCodeLine ("bcc %s", LocalLabelName (L));
1597 AddCodeLine ("inx");
1602 AddCodeLine ("clc");
1603 AddCodeLine ("adc %s", lbuf);
1604 AddCodeLine ("tay");
1605 AddCodeLine ("txa");
1606 AddCodeLine ("adc %s+1", lbuf);
1607 AddCodeLine ("tax");
1608 AddCodeLine ("tya");
1612 /* Do it the old way */
1614 g_getstatic (flags, label, offs);
1626 /*****************************************************************************/
1627 /* Special op= functions */
1628 /*****************************************************************************/
1632 void g_addeqstatic (unsigned flags, unsigned long label, long offs,
1634 /* Emit += for a static variable */
1636 /* Create the correct label name */
1637 const char* lbuf = GetLabelName (flags, label, offs);
1639 /* Check the size and determine operation */
1640 switch (flags & CF_TYPE) {
1643 if (flags & CF_FORCECHAR) {
1644 AddCodeLine ("ldx #$00");
1645 if (flags & CF_CONST) {
1647 AddCodeLine ("inc %s", lbuf);
1648 AddCodeLine ("lda %s", lbuf);
1650 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1651 AddCodeLine ("clc");
1652 AddCodeLine ("adc %s", lbuf);
1653 AddCodeLine ("sta %s", lbuf);
1656 AddCodeLine ("clc");
1657 AddCodeLine ("adc %s", lbuf);
1658 AddCodeLine ("sta %s", lbuf);
1660 if ((flags & CF_UNSIGNED) == 0) {
1661 unsigned L = GetLocalLabel();
1662 AddCodeLine ("bpl %s", LocalLabelName (L));
1663 AddCodeLine ("dex");
1671 if (flags & CF_CONST) {
1673 unsigned L = GetLocalLabel ();
1674 AddCodeLine ("inc %s", lbuf);
1675 AddCodeLine ("bne %s", LocalLabelName (L));
1676 AddCodeLine ("inc %s+1", lbuf);
1678 AddCodeLine ("lda %s", lbuf); /* Hmmm... */
1679 AddCodeLine ("ldx %s+1", lbuf);
1681 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1682 AddCodeLine ("clc");
1683 AddCodeLine ("adc %s", lbuf);
1684 AddCodeLine ("sta %s", lbuf);
1686 unsigned L = GetLocalLabel ();
1687 AddCodeLine ("bcc %s", LocalLabelName (L));
1688 AddCodeLine ("inc %s+1", lbuf);
1690 AddCodeLine ("ldx %s+1", lbuf);
1692 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1693 AddCodeLine ("adc %s+1", lbuf);
1694 AddCodeLine ("sta %s+1", lbuf);
1695 AddCodeLine ("tax");
1696 AddCodeLine ("lda %s", lbuf);
1700 AddCodeLine ("clc");
1701 AddCodeLine ("adc %s", lbuf);
1702 AddCodeLine ("sta %s", lbuf);
1703 AddCodeLine ("txa");
1704 AddCodeLine ("adc %s+1", lbuf);
1705 AddCodeLine ("sta %s+1", lbuf);
1706 AddCodeLine ("tax");
1707 AddCodeLine ("lda %s", lbuf);
1712 if (flags & CF_CONST) {
1714 AddCodeLine ("ldy #<(%s)", lbuf);
1715 AddCodeLine ("sty ptr1");
1716 AddCodeLine ("ldy #>(%s)", lbuf);
1718 AddCodeLine ("jsr laddeq1");
1720 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1721 AddCodeLine ("jsr laddeqa");
1724 g_getstatic (flags, label, offs);
1726 g_putstatic (flags, label, offs);
1729 AddCodeLine ("ldy #<(%s)", lbuf);
1730 AddCodeLine ("sty ptr1");
1731 AddCodeLine ("ldy #>(%s)", lbuf);
1732 AddCodeLine ("jsr laddeq");
1743 void g_addeqlocal (unsigned flags, int Offs, unsigned long val)
1744 /* Emit += for a local variable */
1746 /* Calculate the true offset, check it, load it into Y */
1748 CheckLocalOffs (Offs);
1750 /* Check the size and determine operation */
1751 switch (flags & CF_TYPE) {
1754 if (flags & CF_FORCECHAR) {
1755 AddCodeLine ("ldy #$%02X", Offs);
1756 AddCodeLine ("ldx #$00");
1757 if (flags & CF_CONST) {
1758 AddCodeLine ("clc");
1759 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1760 AddCodeLine ("adc (sp),y");
1761 AddCodeLine ("sta (sp),y");
1763 AddCodeLine ("clc");
1764 AddCodeLine ("adc (sp),y");
1765 AddCodeLine ("sta (sp),y");
1767 if ((flags & CF_UNSIGNED) == 0) {
1768 unsigned L = GetLocalLabel();
1769 AddCodeLine ("bpl %s", LocalLabelName (L));
1770 AddCodeLine ("dex");
1778 AddCodeLine ("ldy #$%02X", Offs);
1779 if (flags & CF_CONST) {
1780 if (IS_Get (&CodeSizeFactor) >= 400) {
1781 AddCodeLine ("clc");
1782 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1783 AddCodeLine ("adc (sp),y");
1784 AddCodeLine ("sta (sp),y");
1785 AddCodeLine ("iny");
1786 AddCodeLine ("lda #$%02X", (int) ((val >> 8) & 0xFF));
1787 AddCodeLine ("adc (sp),y");
1788 AddCodeLine ("sta (sp),y");
1789 AddCodeLine ("tax");
1790 AddCodeLine ("dey");
1791 AddCodeLine ("lda (sp),y");
1793 g_getimmed (flags, val, 0);
1794 AddCodeLine ("jsr addeqysp");
1797 AddCodeLine ("jsr addeqysp");
1802 if (flags & CF_CONST) {
1803 g_getimmed (flags, val, 0);
1805 AddCodeLine ("ldy #$%02X", Offs);
1806 AddCodeLine ("jsr laddeqysp");
1816 void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
1817 /* Emit += for the location with address in ax */
1819 /* If the offset is too large for a byte register, add the high byte
1820 * of the offset to the primary. Beware: We need a special correction
1821 * if the offset in the low byte will overflow in the operation.
1823 offs = MakeByteOffs (flags, offs);
1825 /* Check the size and determine operation */
1826 switch (flags & CF_TYPE) {
1829 AddCodeLine ("sta ptr1");
1830 AddCodeLine ("stx ptr1+1");
1831 AddCodeLine ("ldy #$%02X", offs);
1832 AddCodeLine ("ldx #$00");
1833 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1834 AddCodeLine ("clc");
1835 AddCodeLine ("adc (ptr1),y");
1836 AddCodeLine ("sta (ptr1),y");
1840 if (IS_Get (&CodeSizeFactor) >= 200) {
1841 /* Lots of code, use only if size is not important */
1842 AddCodeLine ("sta ptr1");
1843 AddCodeLine ("stx ptr1+1");
1844 AddCodeLine ("ldy #$%02X", offs);
1845 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1846 AddCodeLine ("clc");
1847 AddCodeLine ("adc (ptr1),y");
1848 AddCodeLine ("sta (ptr1),y");
1849 AddCodeLine ("pha");
1850 AddCodeLine ("iny");
1851 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1852 AddCodeLine ("adc (ptr1),y");
1853 AddCodeLine ("sta (ptr1),y");
1854 AddCodeLine ("tax");
1855 AddCodeLine ("pla");
1861 AddCodeLine ("jsr pushax"); /* Push the address */
1862 push (CF_PTR); /* Correct the internal sp */
1863 g_getind (flags, offs); /* Fetch the value */
1864 g_inc (flags, val); /* Increment value in primary */
1865 g_putind (flags, offs); /* Store the value back */
1875 void g_subeqstatic (unsigned flags, unsigned long label, long offs,
1877 /* Emit -= for a static variable */
1879 /* Create the correct label name */
1880 const char* lbuf = GetLabelName (flags, label, offs);
1882 /* Check the size and determine operation */
1883 switch (flags & CF_TYPE) {
1886 if (flags & CF_FORCECHAR) {
1887 AddCodeLine ("ldx #$00");
1888 if (flags & CF_CONST) {
1890 AddCodeLine ("dec %s", lbuf);
1891 AddCodeLine ("lda %s", lbuf);
1893 AddCodeLine ("lda %s", lbuf);
1894 AddCodeLine ("sec");
1895 AddCodeLine ("sbc #$%02X", (int)(val & 0xFF));
1896 AddCodeLine ("sta %s", lbuf);
1899 AddCodeLine ("eor #$FF");
1900 AddCodeLine ("sec");
1901 AddCodeLine ("adc %s", lbuf);
1902 AddCodeLine ("sta %s", lbuf);
1904 if ((flags & CF_UNSIGNED) == 0) {
1905 unsigned L = GetLocalLabel();
1906 AddCodeLine ("bpl %s", LocalLabelName (L));
1907 AddCodeLine ("dex");
1915 if (flags & CF_CONST) {
1916 AddCodeLine ("lda %s", lbuf);
1917 AddCodeLine ("sec");
1918 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1919 AddCodeLine ("sta %s", lbuf);
1921 unsigned L = GetLocalLabel ();
1922 AddCodeLine ("bcs %s", LocalLabelName (L));
1923 AddCodeLine ("dec %s+1", lbuf);
1925 AddCodeLine ("ldx %s+1", lbuf);
1927 AddCodeLine ("lda %s+1", lbuf);
1928 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
1929 AddCodeLine ("sta %s+1", lbuf);
1930 AddCodeLine ("tax");
1931 AddCodeLine ("lda %s", lbuf);
1934 AddCodeLine ("eor #$FF");
1935 AddCodeLine ("sec");
1936 AddCodeLine ("adc %s", lbuf);
1937 AddCodeLine ("sta %s", lbuf);
1938 AddCodeLine ("txa");
1939 AddCodeLine ("eor #$FF");
1940 AddCodeLine ("adc %s+1", lbuf);
1941 AddCodeLine ("sta %s+1", lbuf);
1942 AddCodeLine ("tax");
1943 AddCodeLine ("lda %s", lbuf);
1948 if (flags & CF_CONST) {
1950 AddCodeLine ("ldy #<(%s)", lbuf);
1951 AddCodeLine ("sty ptr1");
1952 AddCodeLine ("ldy #>(%s)", lbuf);
1953 AddCodeLine ("lda #$%02X", (unsigned char)val);
1954 AddCodeLine ("jsr lsubeqa");
1956 g_getstatic (flags, label, offs);
1958 g_putstatic (flags, label, offs);
1961 AddCodeLine ("ldy #<(%s)", lbuf);
1962 AddCodeLine ("sty ptr1");
1963 AddCodeLine ("ldy #>(%s)", lbuf);
1964 AddCodeLine ("jsr lsubeq");
1975 void g_subeqlocal (unsigned flags, int Offs, unsigned long val)
1976 /* Emit -= for a local variable */
1978 /* Calculate the true offset, check it, load it into Y */
1980 CheckLocalOffs (Offs);
1982 /* Check the size and determine operation */
1983 switch (flags & CF_TYPE) {
1986 if (flags & CF_FORCECHAR) {
1987 AddCodeLine ("ldy #$%02X", Offs);
1988 AddCodeLine ("ldx #$00");
1989 if (flags & CF_CONST) {
1990 AddCodeLine ("lda (sp),y");
1991 AddCodeLine ("sec");
1992 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1994 AddCodeLine ("eor #$FF");
1995 AddCodeLine ("sec");
1996 AddCodeLine ("adc (sp),y");
1998 AddCodeLine ("sta (sp),y");
1999 if ((flags & CF_UNSIGNED) == 0) {
2000 unsigned L = GetLocalLabel();
2001 AddCodeLine ("bpl %s", LocalLabelName (L));
2002 AddCodeLine ("dex");
2010 if (flags & CF_CONST) {
2011 g_getimmed (flags, val, 0);
2013 AddCodeLine ("ldy #$%02X", Offs);
2014 AddCodeLine ("jsr subeqysp");
2018 if (flags & CF_CONST) {
2019 g_getimmed (flags, val, 0);
2021 AddCodeLine ("ldy #$%02X", Offs);
2022 AddCodeLine ("jsr lsubeqysp");
2032 void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
2033 /* Emit -= for the location with address in ax */
2035 /* If the offset is too large for a byte register, add the high byte
2036 * of the offset to the primary. Beware: We need a special correction
2037 * if the offset in the low byte will overflow in the operation.
2039 offs = MakeByteOffs (flags, offs);
2041 /* Check the size and determine operation */
2042 switch (flags & CF_TYPE) {
2045 AddCodeLine ("sta ptr1");
2046 AddCodeLine ("stx ptr1+1");
2047 AddCodeLine ("ldy #$%02X", offs);
2048 AddCodeLine ("ldx #$00");
2049 AddCodeLine ("lda (ptr1),y");
2050 AddCodeLine ("sec");
2051 AddCodeLine ("sbc #$%02X", (unsigned char)val);
2052 AddCodeLine ("sta (ptr1),y");
2056 if (IS_Get (&CodeSizeFactor) >= 200) {
2057 /* Lots of code, use only if size is not important */
2058 AddCodeLine ("sta ptr1");
2059 AddCodeLine ("stx ptr1+1");
2060 AddCodeLine ("ldy #$%02X", offs);
2061 AddCodeLine ("lda (ptr1),y");
2062 AddCodeLine ("sec");
2063 AddCodeLine ("sbc #$%02X", (unsigned char)val);
2064 AddCodeLine ("sta (ptr1),y");
2065 AddCodeLine ("pha");
2066 AddCodeLine ("iny");
2067 AddCodeLine ("lda (ptr1),y");
2068 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
2069 AddCodeLine ("sta (ptr1),y");
2070 AddCodeLine ("tax");
2071 AddCodeLine ("pla");
2077 AddCodeLine ("jsr pushax"); /* Push the address */
2078 push (CF_PTR); /* Correct the internal sp */
2079 g_getind (flags, offs); /* Fetch the value */
2080 g_dec (flags, val); /* Increment value in primary */
2081 g_putind (flags, offs); /* Store the value back */
2091 /*****************************************************************************/
2092 /* Add a variable address to the value in ax */
2093 /*****************************************************************************/
2097 void g_addaddr_local (unsigned flags attribute ((unused)), int offs)
2098 /* Add the address of a local variable to ax */
2102 /* Add the offset */
2105 /* We cannot address more then 256 bytes of locals anyway */
2106 L = GetLocalLabel();
2107 CheckLocalOffs (offs);
2108 AddCodeLine ("clc");
2109 AddCodeLine ("adc #$%02X", offs & 0xFF);
2110 /* Do also skip the CLC insn below */
2111 AddCodeLine ("bcc %s", LocalLabelName (L));
2112 AddCodeLine ("inx");
2115 /* Add the current stackpointer value */
2116 AddCodeLine ("clc");
2118 /* Label was used above */
2121 AddCodeLine ("adc sp");
2122 AddCodeLine ("tay");
2123 AddCodeLine ("txa");
2124 AddCodeLine ("adc sp+1");
2125 AddCodeLine ("tax");
2126 AddCodeLine ("tya");
2131 void g_addaddr_static (unsigned flags, unsigned long label, long offs)
2132 /* Add the address of a static variable to ax */
2134 /* Create the correct label name */
2135 const char* lbuf = GetLabelName (flags, label, offs);
2137 /* Add the address to the current ax value */
2138 AddCodeLine ("clc");
2139 AddCodeLine ("adc #<(%s)", lbuf);
2140 AddCodeLine ("tay");
2141 AddCodeLine ("txa");
2142 AddCodeLine ("adc #>(%s)", lbuf);
2143 AddCodeLine ("tax");
2144 AddCodeLine ("tya");
2149 /*****************************************************************************/
2151 /*****************************************************************************/
2155 void g_save (unsigned flags)
2156 /* Copy primary register to hold register. */
2158 /* Check the size and determine operation */
2159 switch (flags & CF_TYPE) {
2162 if (flags & CF_FORCECHAR) {
2163 AddCodeLine ("pha");
2169 AddCodeLine ("sta regsave");
2170 AddCodeLine ("stx regsave+1");
2174 AddCodeLine ("jsr saveeax");
2184 void g_restore (unsigned flags)
2185 /* Copy hold register to primary. */
2187 /* Check the size and determine operation */
2188 switch (flags & CF_TYPE) {
2191 if (flags & CF_FORCECHAR) {
2192 AddCodeLine ("pla");
2198 AddCodeLine ("lda regsave");
2199 AddCodeLine ("ldx regsave+1");
2203 AddCodeLine ("jsr resteax");
2213 void g_cmp (unsigned flags, unsigned long val)
2214 /* Immidiate compare. The primary register will not be changed, Z flag
2220 /* Check the size and determine operation */
2221 switch (flags & CF_TYPE) {
2224 if (flags & CF_FORCECHAR) {
2225 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2231 L = GetLocalLabel();
2232 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2233 AddCodeLine ("bne %s", LocalLabelName (L));
2234 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
2239 Internal ("g_cmp: Long compares not implemented");
2249 static void oper (unsigned Flags, unsigned long Val, const char** Subs)
2250 /* Encode a binary operation. subs is a pointer to four strings:
2251 * 0 --> Operate on ints
2252 * 1 --> Operate on unsigneds
2253 * 2 --> Operate on longs
2254 * 3 --> Operate on unsigned longs
2257 /* Determine the offset into the array */
2258 if (Flags & CF_UNSIGNED) {
2261 if ((Flags & CF_TYPE) == CF_LONG) {
2265 /* Load the value if it is not already in the primary */
2266 if (Flags & CF_CONST) {
2268 g_getimmed (Flags, Val, 0);
2271 /* Output the operation */
2272 AddCodeLine ("jsr %s", *Subs);
2274 /* The operation will pop it's argument */
2280 void g_test (unsigned flags)
2281 /* Test the value in the primary and set the condition codes */
2283 switch (flags & CF_TYPE) {
2286 if (flags & CF_FORCECHAR) {
2287 AddCodeLine ("tax");
2293 AddCodeLine ("stx tmp1");
2294 AddCodeLine ("ora tmp1");
2298 if (flags & CF_UNSIGNED) {
2299 AddCodeLine ("jsr utsteax");
2301 AddCodeLine ("jsr tsteax");
2313 void g_push (unsigned flags, unsigned long val)
2314 /* Push the primary register or a constant value onto the stack */
2316 if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
2318 /* We have a constant 8 or 16 bit value */
2319 if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
2321 /* Handle as 8 bit value */
2322 AddCodeLine ("lda #$%02X", (unsigned char) val);
2323 AddCodeLine ("jsr pusha");
2327 /* Handle as 16 bit value */
2328 g_getimmed (flags, val, 0);
2329 AddCodeLine ("jsr pushax");
2334 /* Value is not 16 bit or not constant */
2335 if (flags & CF_CONST) {
2336 /* Constant 32 bit value, load into eax */
2337 g_getimmed (flags, val, 0);
2340 /* Push the primary register */
2341 switch (flags & CF_TYPE) {
2344 if (flags & CF_FORCECHAR) {
2345 /* Handle as char */
2346 AddCodeLine ("jsr pusha");
2351 AddCodeLine ("jsr pushax");
2355 AddCodeLine ("jsr pusheax");
2365 /* Adjust the stack offset */
2371 void g_swap (unsigned flags)
2372 /* Swap the primary register and the top of the stack. flags give the type
2373 * of *both* values (must have same size).
2376 switch (flags & CF_TYPE) {
2380 AddCodeLine ("jsr swapstk");
2384 AddCodeLine ("jsr swapestk");
2395 void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
2396 /* Call the specified subroutine name */
2398 if ((Flags & CF_FIXARGC) == 0) {
2399 /* Pass the argument count */
2400 AddCodeLine ("ldy #$%02X", ArgSize);
2402 AddCodeLine ("jsr _%s", Label);
2403 StackPtr += ArgSize; /* callee pops args */
2408 void g_callind (unsigned Flags, unsigned ArgSize, int Offs)
2409 /* Call subroutine indirect */
2411 if ((Flags & CF_LOCAL) == 0) {
2412 /* Address is in a/x */
2413 if ((Flags & CF_FIXARGC) == 0) {
2414 /* Pass arg count */
2415 AddCodeLine ("ldy #$%02X", ArgSize);
2417 AddCodeLine ("jsr callax");
2419 /* The address is on stack, offset is on Val */
2421 CheckLocalOffs (Offs);
2422 AddCodeLine ("pha");
2423 AddCodeLine ("ldy #$%02X", Offs);
2424 AddCodeLine ("lda (sp),y");
2425 AddCodeLine ("sta jmpvec+1");
2426 AddCodeLine ("iny");
2427 AddCodeLine ("lda (sp),y");
2428 AddCodeLine ("sta jmpvec+2");
2429 AddCodeLine ("pla");
2430 AddCodeLine ("jsr jmpvec");
2433 /* Callee pops args */
2434 StackPtr += ArgSize;
2439 void g_jump (unsigned Label)
2440 /* Jump to specified internal label number */
2442 AddCodeLine ("jmp %s", LocalLabelName (Label));
2447 void g_truejump (unsigned flags attribute ((unused)), unsigned label)
2448 /* Jump to label if zero flag clear */
2450 AddCodeLine ("jne %s", LocalLabelName (label));
2455 void g_falsejump (unsigned flags attribute ((unused)), unsigned label)
2456 /* Jump to label if zero flag set */
2458 AddCodeLine ("jeq %s", LocalLabelName (label));
2463 void g_drop (unsigned Space)
2464 /* Drop space allocated on the stack */
2467 /* Inline the code since calling addysp repeatedly is quite some
2470 AddCodeLine ("pha");
2471 AddCodeLine ("lda #$%02X", (unsigned char) Space);
2472 AddCodeLine ("clc");
2473 AddCodeLine ("adc sp");
2474 AddCodeLine ("sta sp");
2475 AddCodeLine ("lda #$%02X", (unsigned char) (Space >> 8));
2476 AddCodeLine ("adc sp+1");
2477 AddCodeLine ("sta sp+1");
2478 AddCodeLine ("pla");
2479 } else if (Space > 8) {
2480 AddCodeLine ("ldy #$%02X", Space);
2481 AddCodeLine ("jsr addysp");
2482 } else if (Space != 0) {
2483 AddCodeLine ("jsr incsp%u", Space);
2489 void g_space (int Space)
2490 /* Create or drop space on the stack */
2493 /* This is actually a drop operation */
2495 } else if (Space > 255) {
2496 /* Inline the code since calling subysp repeatedly is quite some
2499 AddCodeLine ("pha");
2500 AddCodeLine ("lda sp");
2501 AddCodeLine ("sec");
2502 AddCodeLine ("sbc #$%02X", (unsigned char) Space);
2503 AddCodeLine ("sta sp");
2504 AddCodeLine ("lda sp+1");
2505 AddCodeLine ("sbc #$%02X", (unsigned char) (Space >> 8));
2506 AddCodeLine ("sta sp+1");
2507 AddCodeLine ("pla");
2508 } else if (Space > 8) {
2509 AddCodeLine ("ldy #$%02X", Space);
2510 AddCodeLine ("jsr subysp");
2511 } else if (Space != 0) {
2512 AddCodeLine ("jsr decsp%u", Space);
2518 void g_cstackcheck (void)
2519 /* Check for a C stack overflow */
2521 AddCodeLine ("jsr cstkchk");
2526 void g_stackcheck (void)
2527 /* Check for a stack overflow */
2529 AddCodeLine ("jsr stkchk");
2534 void g_add (unsigned flags, unsigned long val)
2535 /* Primary = TOS + Primary */
2537 static const char* ops[12] = {
2538 "tosaddax", "tosaddax", "tosaddeax", "tosaddeax"
2541 if (flags & CF_CONST) {
2542 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2543 g_push (flags & ~CF_CONST, 0);
2545 oper (flags, val, ops);
2550 void g_sub (unsigned flags, unsigned long val)
2551 /* Primary = TOS - Primary */
2553 static const char* ops[12] = {
2554 "tossubax", "tossubax", "tossubeax", "tossubeax",
2557 if (flags & CF_CONST) {
2558 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2559 g_push (flags & ~CF_CONST, 0);
2561 oper (flags, val, ops);
2566 void g_rsub (unsigned flags, unsigned long val)
2567 /* Primary = Primary - TOS */
2569 static const char* ops[12] = {
2570 "tosrsubax", "tosrsubax", "tosrsubeax", "tosrsubeax",
2572 oper (flags, val, ops);
2577 void g_mul (unsigned flags, unsigned long val)
2578 /* Primary = TOS * Primary */
2580 static const char* ops[12] = {
2581 "tosmulax", "tosumulax", "tosmuleax", "tosumuleax",
2586 /* Do strength reduction if the value is constant and a power of two */
2587 if (flags & CF_CONST && (p2 = PowerOf2 (val)) >= 0) {
2588 /* Generate a shift instead */
2593 /* If the right hand side is const, the lhs is not on stack but still
2594 * in the primary register.
2596 if (flags & CF_CONST) {
2598 switch (flags & CF_TYPE) {
2601 if (flags & CF_FORCECHAR) {
2602 /* Handle some special cases */
2606 AddCodeLine ("sta tmp1");
2607 AddCodeLine ("asl a");
2608 AddCodeLine ("clc");
2609 AddCodeLine ("adc tmp1");
2613 AddCodeLine ("sta tmp1");
2614 AddCodeLine ("asl a");
2615 AddCodeLine ("asl a");
2616 AddCodeLine ("clc");
2617 AddCodeLine ("adc tmp1");
2621 AddCodeLine ("sta tmp1");
2622 AddCodeLine ("asl a");
2623 AddCodeLine ("clc");
2624 AddCodeLine ("adc tmp1");
2625 AddCodeLine ("asl a");
2629 AddCodeLine ("sta tmp1");
2630 AddCodeLine ("asl a");
2631 AddCodeLine ("asl a");
2632 AddCodeLine ("clc");
2633 AddCodeLine ("adc tmp1");
2634 AddCodeLine ("asl a");
2643 AddCodeLine ("jsr mulax3");
2646 AddCodeLine ("jsr mulax5");
2649 AddCodeLine ("jsr mulax6");
2652 AddCodeLine ("jsr mulax7");
2655 AddCodeLine ("jsr mulax9");
2658 AddCodeLine ("jsr mulax10");
2670 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2671 * into the normal, non-optimized stuff.
2673 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2674 g_push (flags & ~CF_CONST, 0);
2678 /* Use long way over the stack */
2679 oper (flags, val, ops);
2684 void g_div (unsigned flags, unsigned long val)
2685 /* Primary = TOS / Primary */
2687 static const char* ops[12] = {
2688 "tosdivax", "tosudivax", "tosdiveax", "tosudiveax",
2691 /* Do strength reduction if the value is constant and a power of two */
2693 if ((flags & CF_CONST) && (p2 = PowerOf2 (val)) >= 0) {
2694 /* Generate a shift instead */
2697 /* Generate a division */
2698 if (flags & CF_CONST) {
2699 /* lhs is not on stack */
2700 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2701 g_push (flags & ~CF_CONST, 0);
2703 oper (flags, val, ops);
2709 void g_mod (unsigned flags, unsigned long val)
2710 /* Primary = TOS % Primary */
2712 static const char* ops[12] = {
2713 "tosmodax", "tosumodax", "tosmodeax", "tosumodeax",
2717 /* Check if we can do some cost reduction */
2718 if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = PowerOf2 (val)) >= 0) {
2719 /* We can do that with an AND operation */
2720 g_and (flags, val - 1);
2722 /* Do it the hard way... */
2723 if (flags & CF_CONST) {
2724 /* lhs is not on stack */
2725 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2726 g_push (flags & ~CF_CONST, 0);
2728 oper (flags, val, ops);
2734 void g_or (unsigned flags, unsigned long val)
2735 /* Primary = TOS | Primary */
2737 static const char* ops[12] = {
2738 "tosorax", "tosorax", "tosoreax", "tosoreax",
2741 /* If the right hand side is const, the lhs is not on stack but still
2742 * in the primary register.
2744 if (flags & CF_CONST) {
2746 switch (flags & CF_TYPE) {
2749 if (flags & CF_FORCECHAR) {
2750 if ((val & 0xFF) != 0) {
2751 AddCodeLine ("ora #$%02X", (unsigned char)val);
2759 if ((val & 0xFF) != 0) {
2760 AddCodeLine ("ora #$%02X", (unsigned char)val);
2762 } else if ((val & 0xFF00) == 0xFF00) {
2763 if ((val & 0xFF) != 0) {
2764 AddCodeLine ("ora #$%02X", (unsigned char)val);
2766 AddCodeLine ("ldx #$FF");
2767 } else if (val != 0) {
2768 AddCodeLine ("ora #$%02X", (unsigned char)val);
2769 AddCodeLine ("pha");
2770 AddCodeLine ("txa");
2771 AddCodeLine ("ora #$%02X", (unsigned char)(val >> 8));
2772 AddCodeLine ("tax");
2773 AddCodeLine ("pla");
2779 if ((val & 0xFF) != 0) {
2780 AddCodeLine ("ora #$%02X", (unsigned char)val);
2790 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2791 * into the normal, non-optimized stuff. Note: The standard stuff will
2792 * always work with ints.
2794 flags &= ~CF_FORCECHAR;
2795 g_push (flags & ~CF_CONST, 0);
2798 /* Use long way over the stack */
2799 oper (flags, val, ops);
2804 void g_xor (unsigned flags, unsigned long val)
2805 /* Primary = TOS ^ Primary */
2807 static const char* ops[12] = {
2808 "tosxorax", "tosxorax", "tosxoreax", "tosxoreax",
2812 /* If the right hand side is const, the lhs is not on stack but still
2813 * in the primary register.
2815 if (flags & CF_CONST) {
2817 switch (flags & CF_TYPE) {
2820 if (flags & CF_FORCECHAR) {
2821 if ((val & 0xFF) != 0) {
2822 AddCodeLine ("eor #$%02X", (unsigned char)val);
2831 AddCodeLine ("eor #$%02X", (unsigned char)val);
2833 } else if (val != 0) {
2834 if ((val & 0xFF) != 0) {
2835 AddCodeLine ("eor #$%02X", (unsigned char)val);
2837 AddCodeLine ("pha");
2838 AddCodeLine ("txa");
2839 AddCodeLine ("eor #$%02X", (unsigned char)(val >> 8));
2840 AddCodeLine ("tax");
2841 AddCodeLine ("pla");
2848 AddCodeLine ("eor #$%02X", (unsigned char)val);
2858 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2859 * into the normal, non-optimized stuff. Note: The standard stuff will
2860 * always work with ints.
2862 flags &= ~CF_FORCECHAR;
2863 g_push (flags & ~CF_CONST, 0);
2866 /* Use long way over the stack */
2867 oper (flags, val, ops);
2872 void g_and (unsigned Flags, unsigned long Val)
2873 /* Primary = TOS & Primary */
2875 static const char* ops[12] = {
2876 "tosandax", "tosandax", "tosandeax", "tosandeax",
2879 /* If the right hand side is const, the lhs is not on stack but still
2880 * in the primary register.
2882 if (Flags & CF_CONST) {
2884 switch (Flags & CF_TYPE) {
2887 if (Flags & CF_FORCECHAR) {
2888 if ((Val & 0xFF) == 0x00) {
2889 AddCodeLine ("lda #$00");
2890 } else if ((Val & 0xFF) != 0xFF) {
2891 AddCodeLine ("and #$%02X", (unsigned char)Val);
2897 if ((Val & 0xFFFF) != 0xFFFF) {
2899 AddCodeLine ("ldx #$00");
2901 AddCodeLine ("lda #$00");
2902 } else if (Val != 0xFF) {
2903 AddCodeLine ("and #$%02X", (unsigned char)Val);
2905 } else if ((Val & 0xFFFF) == 0xFF00) {
2906 AddCodeLine ("lda #$00");
2907 } else if ((Val & 0xFF00) == 0xFF00) {
2908 AddCodeLine ("and #$%02X", (unsigned char)Val);
2909 } else if ((Val & 0x00FF) == 0x0000) {
2910 AddCodeLine ("txa");
2911 AddCodeLine ("and #$%02X", (unsigned char)(Val >> 8));
2912 AddCodeLine ("tax");
2913 AddCodeLine ("lda #$00");
2915 AddCodeLine ("tay");
2916 AddCodeLine ("txa");
2917 AddCodeLine ("and #$%02X", (unsigned char)(Val >> 8));
2918 AddCodeLine ("tax");
2919 AddCodeLine ("tya");
2920 if ((Val & 0x00FF) == 0x0000) {
2921 AddCodeLine ("lda #$00");
2922 } else if ((Val & 0x00FF) != 0x00FF) {
2923 AddCodeLine ("and #$%02X", (unsigned char)Val);
2931 AddCodeLine ("ldx #$00");
2932 AddCodeLine ("stx sreg+1");
2933 AddCodeLine ("stx sreg");
2934 if ((Val & 0xFF) != 0xFF) {
2935 AddCodeLine ("and #$%02X", (unsigned char)Val);
2938 } else if (Val == 0xFF00) {
2939 AddCodeLine ("lda #$00");
2940 AddCodeLine ("sta sreg+1");
2941 AddCodeLine ("sta sreg");
2950 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2951 * into the normal, non-optimized stuff. Note: The standard stuff will
2952 * always work with ints.
2954 Flags &= ~CF_FORCECHAR;
2955 g_push (Flags & ~CF_CONST, 0);
2958 /* Use long way over the stack */
2959 oper (Flags, Val, ops);
2964 void g_asr (unsigned flags, unsigned long val)
2965 /* Primary = TOS >> Primary */
2967 static const char* ops[12] = {
2968 "tosasrax", "tosshrax", "tosasreax", "tosshreax",
2971 /* If the right hand side is const, the lhs is not on stack but still
2972 * in the primary register.
2974 if (flags & CF_CONST) {
2976 switch (flags & CF_TYPE) {
2982 if (flags & CF_UNSIGNED) {
2983 AddCodeLine ("txa");
2984 AddCodeLine ("ldx #$00");
2986 unsigned L = GetLocalLabel();
2987 AddCodeLine ("cpx #$80"); /* Sign bit into carry */
2988 AddCodeLine ("txa");
2989 AddCodeLine ("ldx #$00");
2990 AddCodeLine ("bcc %s", LocalLabelName (L));
2991 AddCodeLine ("dex"); /* Make $FF */
2997 if (flags & CF_UNSIGNED) {
2998 AddCodeLine ("jsr shrax4");
3000 AddCodeLine ("jsr asrax4");
3005 if (flags & CF_UNSIGNED) {
3006 AddCodeLine ("jsr shrax%ld", val);
3008 AddCodeLine ("jsr asrax%ld", val);
3016 AddCodeLine ("ldx #$00");
3017 AddCodeLine ("lda sreg+1");
3018 if ((flags & CF_UNSIGNED) == 0) {
3019 unsigned L = GetLocalLabel();
3020 AddCodeLine ("bpl %s", LocalLabelName (L));
3021 AddCodeLine ("dex");
3024 AddCodeLine ("stx sreg");
3025 AddCodeLine ("stx sreg+1");
3029 AddCodeLine ("ldy #$00");
3030 AddCodeLine ("ldx sreg+1");
3031 if ((flags & CF_UNSIGNED) == 0) {
3032 unsigned L = GetLocalLabel();
3033 AddCodeLine ("bpl %s", LocalLabelName (L));
3034 AddCodeLine ("dey");
3037 AddCodeLine ("lda sreg");
3038 AddCodeLine ("sty sreg+1");
3039 AddCodeLine ("sty sreg");
3043 AddCodeLine ("txa");
3044 AddCodeLine ("ldx sreg");
3045 AddCodeLine ("ldy sreg+1");
3046 AddCodeLine ("sty sreg");
3047 if ((flags & CF_UNSIGNED) == 0) {
3048 unsigned L = GetLocalLabel();
3049 AddCodeLine ("cpy #$80");
3050 AddCodeLine ("ldy #$00");
3051 AddCodeLine ("bcc %s", LocalLabelName (L));
3052 AddCodeLine ("dey");
3055 AddCodeLine ("ldy #$00");
3057 AddCodeLine ("sty sreg+1");
3061 if (flags & CF_UNSIGNED) {
3062 AddCodeLine ("jsr shreax4");
3064 AddCodeLine ("jsr asreax4");
3069 if (flags & CF_UNSIGNED) {
3070 AddCodeLine ("jsr shreax%ld", val);
3072 AddCodeLine ("jsr asreax%ld", val);
3081 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3082 * into the normal, non-optimized stuff. Note: The standard stuff will
3083 * always work with ints.
3085 flags &= ~CF_FORCECHAR;
3086 g_push (flags & ~CF_CONST, 0);
3089 /* Use long way over the stack */
3090 oper (flags, val, ops);
3095 void g_asl (unsigned flags, unsigned long val)
3096 /* Primary = TOS << Primary */
3098 static const char* ops[12] = {
3099 "tosaslax", "tosshlax", "tosasleax", "tosshleax",
3103 /* If the right hand side is const, the lhs is not on stack but still
3104 * in the primary register.
3106 if (flags & CF_CONST) {
3108 switch (flags & CF_TYPE) {
3114 AddCodeLine ("tax");
3115 AddCodeLine ("lda #$00");
3119 if (flags & CF_UNSIGNED) {
3120 AddCodeLine ("jsr shlax4");
3122 AddCodeLine ("jsr aslax4");
3127 if (flags & CF_UNSIGNED) {
3128 AddCodeLine ("jsr shlax%ld", val);
3130 AddCodeLine ("jsr aslax%ld", val);
3138 AddCodeLine ("sta sreg+1");
3139 AddCodeLine ("lda #$00");
3140 AddCodeLine ("tax");
3141 AddCodeLine ("sta sreg");
3145 AddCodeLine ("stx sreg+1");
3146 AddCodeLine ("sta sreg");
3147 AddCodeLine ("lda #$00");
3148 AddCodeLine ("tax");
3152 AddCodeLine ("ldy sreg");
3153 AddCodeLine ("sty sreg+1");
3154 AddCodeLine ("stx sreg");
3155 AddCodeLine ("tax");
3156 AddCodeLine ("lda #$00");
3160 if (flags & CF_UNSIGNED) {
3161 AddCodeLine ("jsr shleax4");
3163 AddCodeLine ("jsr asleax4");
3168 if (flags & CF_UNSIGNED) {
3169 AddCodeLine ("jsr shleax%ld", val);
3171 AddCodeLine ("jsr asleax%ld", val);
3180 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3181 * into the normal, non-optimized stuff. Note: The standard stuff will
3182 * always work with ints.
3184 flags &= ~CF_FORCECHAR;
3185 g_push (flags & ~CF_CONST, 0);
3188 /* Use long way over the stack */
3189 oper (flags, val, ops);
3194 void g_neg (unsigned Flags)
3195 /* Primary = -Primary */
3197 switch (Flags & CF_TYPE) {
3200 if (Flags & CF_FORCECHAR) {
3201 AddCodeLine ("eor #$FF");
3202 AddCodeLine ("clc");
3203 AddCodeLine ("adc #$01");
3209 AddCodeLine ("jsr negax");
3213 AddCodeLine ("jsr negeax");
3223 void g_bneg (unsigned flags)
3224 /* Primary = !Primary */
3226 switch (flags & CF_TYPE) {
3229 AddCodeLine ("jsr bnega");
3233 AddCodeLine ("jsr bnegax");
3237 AddCodeLine ("jsr bnegeax");
3247 void g_com (unsigned Flags)
3248 /* Primary = ~Primary */
3250 switch (Flags & CF_TYPE) {
3253 if (Flags & CF_FORCECHAR) {
3254 AddCodeLine ("eor #$FF");
3260 AddCodeLine ("jsr complax");
3264 AddCodeLine ("jsr compleax");
3274 void g_inc (unsigned flags, unsigned long val)
3275 /* Increment the primary register by a given number */
3277 /* Don't inc by zero */
3282 /* Generate code for the supported types */
3284 switch (flags & CF_TYPE) {
3287 if (flags & CF_FORCECHAR) {
3288 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val <= 2) {
3290 AddCodeLine ("ina");
3293 AddCodeLine ("clc");
3294 AddCodeLine ("adc #$%02X", (unsigned char)val);
3301 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val == 1) {
3302 unsigned L = GetLocalLabel();
3303 AddCodeLine ("ina");
3304 AddCodeLine ("bne %s", LocalLabelName (L));
3305 AddCodeLine ("inx");
3307 } else if (IS_Get (&CodeSizeFactor) < 200) {
3310 AddCodeLine ("jsr incax%lu", val);
3311 } else if (val <= 255) {
3312 AddCodeLine ("ldy #$%02X", (unsigned char) val);
3313 AddCodeLine ("jsr incaxy");
3315 g_add (flags | CF_CONST, val);
3318 /* Inline the code */
3320 if ((val & 0xFF) != 0) {
3321 unsigned L = GetLocalLabel();
3322 AddCodeLine ("clc");
3323 AddCodeLine ("adc #$%02X", (unsigned char) val);
3324 AddCodeLine ("bcc %s", LocalLabelName (L));
3325 AddCodeLine ("inx");
3329 AddCodeLine ("inx");
3332 AddCodeLine ("inx");
3335 AddCodeLine ("inx");
3337 } else if ((val & 0xFF) != 0) {
3338 AddCodeLine ("clc");
3339 AddCodeLine ("adc #$%02X", (unsigned char) val);
3340 AddCodeLine ("pha");
3341 AddCodeLine ("txa");
3342 AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3343 AddCodeLine ("tax");
3344 AddCodeLine ("pla");
3346 AddCodeLine ("pha");
3347 AddCodeLine ("txa");
3348 AddCodeLine ("clc");
3349 AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3350 AddCodeLine ("tax");
3351 AddCodeLine ("pla");
3358 AddCodeLine ("ldy #$%02X", (unsigned char) val);
3359 AddCodeLine ("jsr inceaxy");
3361 g_add (flags | CF_CONST, val);
3373 void g_dec (unsigned flags, unsigned long val)
3374 /* Decrement the primary register by a given number */
3376 /* Don't dec by zero */
3381 /* Generate code for the supported types */
3383 switch (flags & CF_TYPE) {
3386 if (flags & CF_FORCECHAR) {
3387 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val <= 2) {
3389 AddCodeLine ("dea");
3392 AddCodeLine ("sec");
3393 AddCodeLine ("sbc #$%02X", (unsigned char)val);
3400 if (IS_Get (&CodeSizeFactor) < 200) {
3401 /* Use subroutines */
3403 AddCodeLine ("jsr decax%d", (int) val);
3404 } else if (val <= 255) {
3405 AddCodeLine ("ldy #$%02X", (unsigned char) val);
3406 AddCodeLine ("jsr decaxy");
3408 g_sub (flags | CF_CONST, val);
3411 /* Inline the code */
3413 if ((val & 0xFF) != 0) {
3414 unsigned L = GetLocalLabel();
3415 AddCodeLine ("sec");
3416 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3417 AddCodeLine ("bcs %s", LocalLabelName (L));
3418 AddCodeLine ("dex");
3422 AddCodeLine ("dex");
3425 AddCodeLine ("dex");
3428 if ((val & 0xFF) != 0) {
3429 AddCodeLine ("sec");
3430 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3431 AddCodeLine ("pha");
3432 AddCodeLine ("txa");
3433 AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3434 AddCodeLine ("tax");
3435 AddCodeLine ("pla");
3437 AddCodeLine ("pha");
3438 AddCodeLine ("txa");
3439 AddCodeLine ("sec");
3440 AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3441 AddCodeLine ("tax");
3442 AddCodeLine ("pla");
3450 AddCodeLine ("ldy #$%02X", (unsigned char) val);
3451 AddCodeLine ("jsr deceaxy");
3453 g_sub (flags | CF_CONST, val);
3466 * Following are the conditional operators. They compare the TOS against
3467 * the primary and put a literal 1 in the primary if the condition is
3468 * true, otherwise they clear the primary register
3473 void g_eq (unsigned flags, unsigned long val)
3474 /* Test for equal */
3476 static const char* ops[12] = {
3477 "toseqax", "toseqax", "toseqeax", "toseqeax",
3482 /* If the right hand side is const, the lhs is not on stack but still
3483 * in the primary register.
3485 if (flags & CF_CONST) {
3487 switch (flags & CF_TYPE) {
3490 if (flags & CF_FORCECHAR) {
3491 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3492 AddCodeLine ("jsr booleq");
3498 L = GetLocalLabel();
3499 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3500 AddCodeLine ("bne %s", LocalLabelName (L));
3501 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3503 AddCodeLine ("jsr booleq");
3513 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3514 * into the normal, non-optimized stuff. Note: The standard stuff will
3515 * always work with ints.
3517 flags &= ~CF_FORCECHAR;
3518 g_push (flags & ~CF_CONST, 0);
3521 /* Use long way over the stack */
3522 oper (flags, val, ops);
3527 void g_ne (unsigned flags, unsigned long val)
3528 /* Test for not equal */
3530 static const char* ops[12] = {
3531 "tosneax", "tosneax", "tosneeax", "tosneeax",
3536 /* If the right hand side is const, the lhs is not on stack but still
3537 * in the primary register.
3539 if (flags & CF_CONST) {
3541 switch (flags & CF_TYPE) {
3544 if (flags & CF_FORCECHAR) {
3545 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3546 AddCodeLine ("jsr boolne");
3552 L = GetLocalLabel();
3553 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3554 AddCodeLine ("bne %s", LocalLabelName (L));
3555 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3557 AddCodeLine ("jsr boolne");
3567 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3568 * into the normal, non-optimized stuff. Note: The standard stuff will
3569 * always work with ints.
3571 flags &= ~CF_FORCECHAR;
3572 g_push (flags & ~CF_CONST, 0);
3575 /* Use long way over the stack */
3576 oper (flags, val, ops);
3581 void g_lt (unsigned flags, unsigned long val)
3582 /* Test for less than */
3584 static const char* ops[12] = {
3585 "tosltax", "tosultax", "toslteax", "tosulteax",
3590 /* If the right hand side is const, the lhs is not on stack but still
3591 * in the primary register.
3593 if (flags & CF_CONST) {
3595 /* Because the handling of the overflow flag is too complex for
3596 * inlining, we can handle only unsigned compares, and signed
3597 * compares against zero here.
3599 if (flags & CF_UNSIGNED) {
3601 /* Give a warning in some special cases */
3603 Warning ("Condition is never true");
3604 AddCodeLine ("jsr return0");
3608 /* Look at the type */
3609 switch (flags & CF_TYPE) {
3612 if (flags & CF_FORCECHAR) {
3613 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3614 AddCodeLine ("jsr boolult");
3620 /* If the low byte is zero, we must only test the high byte */
3621 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3622 if ((val & 0xFF) != 0) {
3623 unsigned L = GetLocalLabel();
3624 AddCodeLine ("bne %s", LocalLabelName (L));
3625 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3628 AddCodeLine ("jsr boolult");
3632 /* Do a subtraction */
3633 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3634 AddCodeLine ("txa");
3635 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
3636 AddCodeLine ("lda sreg");
3637 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 16));
3638 AddCodeLine ("lda sreg+1");
3639 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 24));
3640 AddCodeLine ("jsr boolult");
3647 } else if (val == 0) {
3649 /* A signed compare against zero must only look at the sign bit */
3650 switch (flags & CF_TYPE) {
3653 if (flags & CF_FORCECHAR) {
3654 AddCodeLine ("asl a"); /* Bit 7 -> carry */
3655 AddCodeLine ("lda #$00");
3656 AddCodeLine ("ldx #$00");
3657 AddCodeLine ("rol a");
3663 /* Just check the high byte */
3664 AddCodeLine ("cpx #$80"); /* Bit 7 -> carry */
3665 AddCodeLine ("lda #$00");
3666 AddCodeLine ("ldx #$00");
3667 AddCodeLine ("rol a");
3671 /* Just check the high byte */
3672 AddCodeLine ("lda sreg+1");
3673 AddCodeLine ("asl a"); /* Bit 7 -> carry */
3674 AddCodeLine ("lda #$00");
3675 AddCodeLine ("ldx #$00");
3676 AddCodeLine ("rol a");
3685 /* Signed compare against a constant != zero */
3686 switch (flags & CF_TYPE) {
3689 if (flags & CF_FORCECHAR) {
3690 Label = GetLocalLabel ();
3691 AddCodeLine ("sec");
3692 AddCodeLine ("sbc #$%02X", (unsigned char)val);
3693 AddCodeLine ("bvc %s", LocalLabelName (Label));
3694 AddCodeLine ("eor #$80");
3695 g_defcodelabel (Label);
3696 AddCodeLine ("asl a"); /* Bit 7 -> carry */
3697 AddCodeLine ("lda #$00");
3698 AddCodeLine ("ldx #$00");
3699 AddCodeLine ("rol a");
3705 /* Do a subtraction */
3706 Label = GetLocalLabel ();
3707 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3708 AddCodeLine ("txa");
3709 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
3710 AddCodeLine ("bvc %s", LocalLabelName (Label));
3711 AddCodeLine ("eor #$80");
3712 g_defcodelabel (Label);
3713 AddCodeLine ("asl a"); /* Bit 7 -> carry */
3714 AddCodeLine ("lda #$00");
3715 AddCodeLine ("ldx #$00");
3716 AddCodeLine ("rol a");
3720 /* This one is too costly */
3729 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3730 * into the normal, non-optimized stuff. Note: The standard stuff will
3731 * always work with ints.
3733 flags &= ~CF_FORCECHAR;
3734 g_push (flags & ~CF_CONST, 0);
3737 /* Use long way over the stack */
3738 oper (flags, val, ops);
3743 void g_le (unsigned flags, unsigned long val)
3744 /* Test for less than or equal to */
3746 static const char* ops[12] = {
3747 "tosleax", "tosuleax", "tosleeax", "tosuleeax",
3751 /* If the right hand side is const, the lhs is not on stack but still
3752 * in the primary register.
3754 if (flags & CF_CONST) {
3756 /* Look at the type */
3757 switch (flags & CF_TYPE) {
3760 if (flags & CF_FORCECHAR) {
3761 if (flags & CF_UNSIGNED) {
3762 /* Unsigned compare */
3764 /* Use < instead of <= because the former gives
3765 * better code on the 6502 than the latter.
3767 g_lt (flags, val+1);
3770 Warning ("Condition is always true");
3771 AddCodeLine ("jsr return1");
3774 /* Signed compare */
3775 if ((long) val < 0x7F) {
3776 /* Use < instead of <= because the former gives
3777 * better code on the 6502 than the latter.
3779 g_lt (flags, val+1);
3782 Warning ("Condition is always true");
3783 AddCodeLine ("jsr return1");
3791 if (flags & CF_UNSIGNED) {
3792 /* Unsigned compare */
3794 /* Use < instead of <= because the former gives
3795 * better code on the 6502 than the latter.
3797 g_lt (flags, val+1);
3800 Warning ("Condition is always true");
3801 AddCodeLine ("jsr return1");
3804 /* Signed compare */
3805 if ((long) val < 0x7FFF) {
3806 g_lt (flags, val+1);
3809 Warning ("Condition is always true");
3810 AddCodeLine ("jsr return1");
3816 if (flags & CF_UNSIGNED) {
3817 /* Unsigned compare */
3818 if (val < 0xFFFFFFFF) {
3819 /* Use < instead of <= because the former gives
3820 * better code on the 6502 than the latter.
3822 g_lt (flags, val+1);
3825 Warning ("Condition is always true");
3826 AddCodeLine ("jsr return1");
3829 /* Signed compare */
3830 if ((long) val < 0x7FFFFFFF) {
3831 g_lt (flags, val+1);
3834 Warning ("Condition is always true");
3835 AddCodeLine ("jsr return1");
3844 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3845 * into the normal, non-optimized stuff. Note: The standard stuff will
3846 * always work with ints.
3848 flags &= ~CF_FORCECHAR;
3849 g_push (flags & ~CF_CONST, 0);
3852 /* Use long way over the stack */
3853 oper (flags, val, ops);
3858 void g_gt (unsigned flags, unsigned long val)
3859 /* Test for greater than */
3861 static const char* ops[12] = {
3862 "tosgtax", "tosugtax", "tosgteax", "tosugteax",
3866 /* If the right hand side is const, the lhs is not on stack but still
3867 * in the primary register.
3869 if (flags & CF_CONST) {
3871 /* Look at the type */
3872 switch (flags & CF_TYPE) {
3875 if (flags & CF_FORCECHAR) {
3876 if (flags & CF_UNSIGNED) {
3878 /* If we have a compare > 0, we will replace it by
3879 * != 0 here, since both are identical but the
3880 * latter is easier to optimize.
3883 } else if (val < 0xFF) {
3884 /* Use >= instead of > because the former gives
3885 * better code on the 6502 than the latter.
3887 g_ge (flags, val+1);
3890 Warning ("Condition is never true");
3891 AddCodeLine ("jsr return0");
3894 if ((long) val < 0x7F) {
3895 /* Use >= instead of > because the former gives
3896 * better code on the 6502 than the latter.
3898 g_ge (flags, val+1);
3901 Warning ("Condition is never true");
3902 AddCodeLine ("jsr return0");
3910 if (flags & CF_UNSIGNED) {
3911 /* Unsigned compare */
3913 /* If we have a compare > 0, we will replace it by
3914 * != 0 here, since both are identical but the latter
3915 * is easier to optimize.
3918 } else if (val < 0xFFFF) {
3919 /* Use >= instead of > because the former gives better
3920 * code on the 6502 than the latter.
3922 g_ge (flags, val+1);
3925 Warning ("Condition is never true");
3926 AddCodeLine ("jsr return0");
3929 /* Signed compare */
3930 if ((long) val < 0x7FFF) {
3931 g_ge (flags, val+1);
3934 Warning ("Condition is never true");
3935 AddCodeLine ("jsr return0");
3941 if (flags & CF_UNSIGNED) {
3942 /* Unsigned compare */
3944 /* If we have a compare > 0, we will replace it by
3945 * != 0 here, since both are identical but the latter
3946 * is easier to optimize.
3949 } else if (val < 0xFFFFFFFF) {
3950 /* Use >= instead of > because the former gives better
3951 * code on the 6502 than the latter.
3953 g_ge (flags, val+1);
3956 Warning ("Condition is never true");
3957 AddCodeLine ("jsr return0");
3960 /* Signed compare */
3961 if ((long) val < 0x7FFFFFFF) {
3962 g_ge (flags, val+1);
3965 Warning ("Condition is never true");
3966 AddCodeLine ("jsr return0");
3975 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3976 * into the normal, non-optimized stuff. Note: The standard stuff will
3977 * always work with ints.
3979 flags &= ~CF_FORCECHAR;
3980 g_push (flags & ~CF_CONST, 0);
3983 /* Use long way over the stack */
3984 oper (flags, val, ops);
3989 void g_ge (unsigned flags, unsigned long val)
3990 /* Test for greater than or equal to */
3992 static const char* ops[12] = {
3993 "tosgeax", "tosugeax", "tosgeeax", "tosugeeax",
3999 /* If the right hand side is const, the lhs is not on stack but still
4000 * in the primary register.
4002 if (flags & CF_CONST) {
4004 /* Because the handling of the overflow flag is too complex for
4005 * inlining, we can handle only unsigned compares, and signed
4006 * compares against zero here.
4008 if (flags & CF_UNSIGNED) {
4010 /* Give a warning in some special cases */
4012 Warning ("Condition is always true");
4013 AddCodeLine ("jsr return1");
4017 /* Look at the type */
4018 switch (flags & CF_TYPE) {
4021 if (flags & CF_FORCECHAR) {
4022 /* Do a subtraction. Condition is true if carry set */
4023 AddCodeLine ("cmp #$%02X", (unsigned char)val);
4024 AddCodeLine ("lda #$00");
4025 AddCodeLine ("ldx #$00");
4026 AddCodeLine ("rol a");
4032 /* Do a subtraction. Condition is true if carry set */
4033 AddCodeLine ("cmp #$%02X", (unsigned char)val);
4034 AddCodeLine ("txa");
4035 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
4036 AddCodeLine ("lda #$00");
4037 AddCodeLine ("ldx #$00");
4038 AddCodeLine ("rol a");
4042 /* Do a subtraction. Condition is true if carry set */
4043 AddCodeLine ("cmp #$%02X", (unsigned char)val);
4044 AddCodeLine ("txa");
4045 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
4046 AddCodeLine ("lda sreg");
4047 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 16));
4048 AddCodeLine ("lda sreg+1");
4049 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 24));
4050 AddCodeLine ("lda #$00");
4051 AddCodeLine ("ldx #$00");
4052 AddCodeLine ("rol a");
4059 } else if (val == 0) {
4061 /* A signed compare against zero must only look at the sign bit */
4062 switch (flags & CF_TYPE) {
4065 if (flags & CF_FORCECHAR) {
4066 AddCodeLine ("tax");
4067 AddCodeLine ("jsr boolge");
4073 /* Just test the high byte */
4074 AddCodeLine ("txa");
4075 AddCodeLine ("jsr boolge");
4079 /* Just test the high byte */
4080 AddCodeLine ("lda sreg+1");
4081 AddCodeLine ("jsr boolge");
4090 /* Signed compare against a constant != zero */
4091 switch (flags & CF_TYPE) {
4094 if (flags & CF_FORCECHAR) {
4095 Label = GetLocalLabel ();
4096 AddCodeLine ("sec");
4097 AddCodeLine ("sbc #$%02X", (unsigned char)val);
4098 AddCodeLine ("bvs %s", LocalLabelName (Label));
4099 AddCodeLine ("eor #$80");
4100 g_defcodelabel (Label);
4101 AddCodeLine ("asl a"); /* Bit 7 -> carry */
4102 AddCodeLine ("lda #$00");
4103 AddCodeLine ("ldx #$00");
4104 AddCodeLine ("rol a");
4110 /* Do a subtraction */
4111 Label = GetLocalLabel ();
4112 AddCodeLine ("cmp #$%02X", (unsigned char)val);
4113 AddCodeLine ("txa");
4114 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
4115 AddCodeLine ("bvs %s", LocalLabelName (Label));
4116 AddCodeLine ("eor #$80");
4117 g_defcodelabel (Label);
4118 AddCodeLine ("asl a"); /* Bit 7 -> carry */
4119 AddCodeLine ("lda #$00");
4120 AddCodeLine ("ldx #$00");
4121 AddCodeLine ("rol a");
4125 /* This one is too costly */
4133 /* If we go here, we didn't emit code. Push the lhs on stack and fall
4134 * into the normal, non-optimized stuff. Note: The standard stuff will
4135 * always work with ints.
4137 flags &= ~CF_FORCECHAR;
4138 g_push (flags & ~CF_CONST, 0);
4141 /* Use long way over the stack */
4142 oper (flags, val, ops);
4147 /*****************************************************************************/
4148 /* Allocating static storage */
4149 /*****************************************************************************/
4153 void g_res (unsigned n)
4154 /* Reserve static storage, n bytes */
4156 AddDataLine ("\t.res\t%u,$00", n);
4161 void g_defdata (unsigned flags, unsigned long val, long offs)
4162 /* Define data with the size given in flags */
4164 if (flags & CF_CONST) {
4166 /* Numeric constant */
4167 switch (flags & CF_TYPE) {
4170 AddDataLine ("\t.byte\t$%02lX", val & 0xFF);
4174 AddDataLine ("\t.word\t$%04lX", val & 0xFFFF);
4178 AddDataLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
4189 /* Create the correct label name */
4190 const char* Label = GetLabelName (flags, val, offs);
4192 /* Labels are always 16 bit */
4193 AddDataLine ("\t.addr\t%s", Label);
4200 void g_defbytes (const void* Bytes, unsigned Count)
4201 /* Output a row of bytes as a constant */
4207 /* Cast the buffer pointer */
4208 const unsigned char* Data = (const unsigned char*) Bytes;
4210 /* Output the stuff */
4213 /* How many go into this line? */
4214 if ((Chunk = Count) > 16) {
4219 /* Output one line */
4220 strcpy (Buf, "\t.byte\t");
4223 B += sprintf (B, "$%02X", *Data++);
4229 /* Output the line */
4230 AddDataLine ("%s", Buf);
4236 void g_zerobytes (unsigned Count)
4237 /* Output Count bytes of data initialized with zero */
4240 AddDataLine ("\t.res\t%u,$00", Count);
4246 void g_initregister (unsigned Label, unsigned Reg, unsigned Size)
4247 /* Initialize a register variable from static initialization data */
4249 /* Register variables do always have less than 128 bytes */
4250 unsigned CodeLabel = GetLocalLabel ();
4251 AddCodeLine ("ldx #$%02X", (unsigned char) (Size - 1));
4252 g_defcodelabel (CodeLabel);
4253 AddCodeLine ("lda %s,x", GetLabelName (CF_STATIC, Label, 0));
4254 AddCodeLine ("sta %s,x", GetLabelName (CF_REGVAR, Reg, 0));
4255 AddCodeLine ("dex");
4256 AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4261 void g_initauto (unsigned Label, unsigned Size)
4262 /* Initialize a local variable at stack offset zero from static data */
4264 unsigned CodeLabel = GetLocalLabel ();
4266 CheckLocalOffs (Size);
4268 AddCodeLine ("ldy #$%02X", Size-1);
4269 g_defcodelabel (CodeLabel);
4270 AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, Label, 0));
4271 AddCodeLine ("sta (sp),y");
4272 AddCodeLine ("dey");
4273 AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4274 } else if (Size <= 256) {
4275 AddCodeLine ("ldy #$00");
4276 g_defcodelabel (CodeLabel);
4277 AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, Label, 0));
4278 AddCodeLine ("sta (sp),y");
4279 AddCodeLine ("iny");
4280 AddCodeLine ("cpy #$%02X", (unsigned char) Size);
4281 AddCodeLine ("bne %s", LocalLabelName (CodeLabel));
4287 void g_initstatic (unsigned InitLabel, unsigned VarLabel, unsigned Size)
4288 /* Initialize a static local variable from static initialization data */
4291 unsigned CodeLabel = GetLocalLabel ();
4292 AddCodeLine ("ldy #$%02X", Size-1);
4293 g_defcodelabel (CodeLabel);
4294 AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, InitLabel, 0));
4295 AddCodeLine ("sta %s,y", GetLabelName (CF_STATIC, VarLabel, 0));
4296 AddCodeLine ("dey");
4297 AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4298 } else if (Size <= 256) {
4299 unsigned CodeLabel = GetLocalLabel ();
4300 AddCodeLine ("ldy #$00");
4301 g_defcodelabel (CodeLabel);
4302 AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, InitLabel, 0));
4303 AddCodeLine ("sta %s,y", GetLabelName (CF_STATIC, VarLabel, 0));
4304 AddCodeLine ("iny");
4305 AddCodeLine ("cpy #$%02X", (unsigned char) Size);
4306 AddCodeLine ("bne %s", LocalLabelName (CodeLabel));
4308 /* Use the easy way here: memcpy */
4309 g_getimmed (CF_STATIC, VarLabel, 0);
4310 AddCodeLine ("jsr pushax");
4311 g_getimmed (CF_STATIC, InitLabel, 0);
4312 AddCodeLine ("jsr pushax");
4313 g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, Size, 0);
4314 AddCodeLine ("jsr %s", GetLabelName (CF_EXTERNAL, (unsigned long) "memcpy", 0));
4320 /*****************************************************************************/
4321 /* Switch statement */
4322 /*****************************************************************************/
4326 void g_switch (Collection* Nodes, unsigned DefaultLabel, unsigned Depth)
4327 /* Generate code for a switch statement */
4329 unsigned NextLabel = 0;
4332 /* Setup registers and determine which compare insn to use */
4333 const char* Compare;
4336 Compare = "cmp #$%02X";
4339 Compare = "cpx #$%02X";
4342 AddCodeLine ("ldy sreg");
4343 Compare = "cpy #$%02X";
4346 AddCodeLine ("ldy sreg+1");
4347 Compare = "cpy #$%02X";
4350 Internal ("Invalid depth in g_switch: %u", Depth);
4353 /* Walk over all nodes */
4354 for (I = 0; I < CollCount (Nodes); ++I) {
4356 /* Get the next case node */
4357 CaseNode* N = CollAtUnchecked (Nodes, I);
4359 /* If we have a next label, define it */
4361 g_defcodelabel (NextLabel);
4365 /* Do the compare */
4366 AddCodeLine (Compare, CN_GetValue (N));
4368 /* If this is the last level, jump directly to the case code if found */
4371 /* Branch if equal */
4372 g_falsejump (0, CN_GetLabel (N));
4376 /* Determine the next label */
4377 if (I == CollCount (Nodes) - 1) {
4378 /* Last node means not found */
4379 g_truejump (0, DefaultLabel);
4381 /* Jump to the next check */
4382 NextLabel = GetLocalLabel ();
4383 g_truejump (0, NextLabel);
4386 /* Check the next level */
4387 g_switch (N->Nodes, DefaultLabel, Depth-1);
4392 /* If we go here, we haven't found the label */
4393 g_jump (DefaultLabel);
4398 /*****************************************************************************/
4399 /* User supplied assembler code */
4400 /*****************************************************************************/
4404 void g_asmcode (struct StrBuf* B)
4405 /* Output one line of assembler code. */
4407 AddCodeLine ("%.*s", (int) SB_GetLen (B), SB_GetConstBuf (B));