]> git.sur5r.net Git - cc65/blob - src/cc65/codegen.c
Finished indirect function calls.
[cc65] / src / cc65 / codegen.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 codegen.c                                 */
4 /*                                                                           */
5 /*                            6502 code generator                            */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2001 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdarg.h>
39
40 /* common */
41 #include "check.h"
42 #include "strbuf.h"
43 #include "version.h"
44 #include "xmalloc.h"
45 #include "xsprintf.h"
46
47 /* cc65 */
48 #include "asmcode.h"
49 #include "asmlabel.h"
50 #include "codeseg.h"
51 #include "cpu.h"
52 #include "dataseg.h"
53 #include "error.h"
54 #include "global.h"
55 #include "segments.h"
56 #include "textseg.h"
57 #include "util.h"
58 #include "codegen.h"
59
60
61
62 /*****************************************************************************/
63 /*                                   Data                                    */
64 /*****************************************************************************/
65
66
67
68 /* Compiler relative stack pointer */
69 int oursp       = 0;
70
71
72
73 /*****************************************************************************/
74 /*                                  Helpers                                  */
75 /*****************************************************************************/
76
77
78
79 static void typeerror (unsigned type)
80 /* Print an error message about an invalid operand type */
81 {
82     Internal ("Invalid type in CF flags: %04X, type = %u", type, type & CF_TYPE);
83 }
84
85
86
87 static void CheckLocalOffs (unsigned Offs)
88 /* Check the offset into the stack for 8bit range */
89 {
90     if (Offs >= 256) {
91         /* Too many local vars */
92         Error ("Too many local variables");
93     }
94 }
95
96
97
98 static char* GetLabelName (unsigned flags, unsigned long label, unsigned offs)
99 {
100     static char lbuf [128];             /* Label name */
101
102     /* Create the correct label name */
103     switch (flags & CF_ADDRMASK) {
104
105         case CF_STATIC:
106             /* Static memory cell */
107             sprintf (lbuf, "%s+%u", LocalLabelName (label), offs);
108             break;
109
110         case CF_EXTERNAL:
111             /* External label */
112             sprintf (lbuf, "_%s+%u", (char*) label, offs);
113             break;
114
115         case CF_ABSOLUTE:
116             /* Absolute address */
117             sprintf (lbuf, "$%04X", (unsigned)((label+offs) & 0xFFFF));
118             break;
119
120         case CF_REGVAR:
121             /* Variable in register bank */
122             sprintf (lbuf, "regbank+%u", (unsigned)((label+offs) & 0xFFFF));
123             break;
124
125         default:
126             Internal ("Invalid address flags");
127     }
128
129     /* Return a pointer to the static buffer */
130     return lbuf;
131 }
132
133
134
135 /*****************************************************************************/
136 /*                            Pre- and postamble                             */
137 /*****************************************************************************/
138
139
140
141 void g_preamble (void)
142 /* Generate the assembler code preamble */
143 {
144     /* Create a new (global) segment list and remember it */
145     PushSegments (0);
146     GS = CS;
147
148     /* Identify the compiler version */
149     AddTextLine (";");
150     AddTextLine ("; File generated by cc65 v %u.%u.%u",
151                  VER_MAJOR, VER_MINOR, VER_PATCH);
152     AddTextLine (";");
153
154     /* Insert some object file options */
155     AddTextLine ("\t.fopt\t\tcompiler,\"cc65 v %u.%u.%u\"",
156                     VER_MAJOR, VER_MINOR, VER_PATCH);
157
158     /* If we're producing code for some other CPU, switch the command set */
159     if (CPU == CPU_65C02) {
160         AddTextLine ("\t.pc02");
161     }
162
163     /* Allow auto import for runtime library routines */
164     AddTextLine ("\t.autoimport\ton");
165
166     /* Switch the assembler into case sensitive mode */
167     AddTextLine ("\t.case\t\ton");
168
169     /* Tell the assembler if we want to generate debug info */
170     AddTextLine ("\t.debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
171
172     /* Import the stack pointer for direct auto variable access */
173     AddTextLine ("\t.importzp\tsp, sreg, regsave, regbank, tmp1, ptr1");
174
175     /* Define long branch macros */
176     AddTextLine ("\t.macpack\tlongbranch");
177 }
178
179
180
181 void g_fileinfo (const char* Name, unsigned long Size, unsigned long MTime)
182 /* If debug info is enabled, place a file info into the source */
183 {
184     if (DebugInfo) {
185         /* We have to place this into the global text segment, so it will
186          * appear before all .dbg line statements.
187          */
188         TS_AddLine (GS->Text, "\t.dbg\t\tfile, \"%s\", %lu, %lu", Name, Size, MTime);
189     }
190 }
191
192
193
194 /*****************************************************************************/
195 /*                              Segment support                              */
196 /*****************************************************************************/
197
198
199
200 void g_userodata (void)
201 /* Switch to the read only data segment */
202 {
203     UseDataSeg (SEG_RODATA);
204 }
205
206
207
208 void g_usedata (void)
209 /* Switch to the data segment */
210 {
211     UseDataSeg (SEG_DATA);
212 }
213
214
215
216 void g_usebss (void)
217 /* Switch to the bss segment */
218 {
219     UseDataSeg (SEG_BSS);
220 }
221
222
223
224 void g_segname (segment_t Seg, const char* Name)
225 /* Set the name of a segment */
226 {
227     DataSeg* S;
228
229     /* Remember the new name */
230     NewSegName (Seg, Name);
231
232     /* Emit a segment directive for the data style segments */
233     switch (Seg) {
234         case SEG_RODATA: S = CS->ROData; break;
235         case SEG_DATA:   S = CS->Data;   break;
236         case SEG_BSS:    S = CS->BSS;    break;
237         default:         S = 0;          break;
238     }
239     if (S) {
240         DS_AddLine (S, ".segment\t\"%s\"", Name);
241     }
242 }
243
244
245
246 /*****************************************************************************/
247 /*                                   Code                                    */
248 /*****************************************************************************/
249
250
251
252 unsigned sizeofarg (unsigned flags)
253 /* Return the size of a function argument type that is encoded in flags */
254 {
255     switch (flags & CF_TYPE) {
256
257         case CF_CHAR:
258             return (flags & CF_FORCECHAR)? 1 : 2;
259
260         case CF_INT:
261             return 2;
262
263         case CF_LONG:
264             return 4;
265
266         default:
267             typeerror (flags);
268             /* NOTREACHED */
269             return 2;
270     }
271 }
272
273
274
275 int pop (unsigned flags)
276 /* Pop an argument of the given size */
277 {
278     return oursp += sizeofarg (flags);
279 }
280
281
282
283 int push (unsigned flags)
284 /* Push an argument of the given size */
285 {
286     return oursp -= sizeofarg (flags);
287 }
288
289
290
291 static unsigned MakeByteOffs (unsigned Flags, unsigned Offs)
292 /* The value in Offs is an offset to an address in a/x. Make sure, an object
293  * of the type given in Flags can be loaded or stored into this address by
294  * adding part of the offset to the address in ax, so that the remaining
295  * offset fits into an index register. Return the remaining offset.
296  */
297 {
298     /* If the offset is too large for a byte register, add the high byte
299      * of the offset to the primary. Beware: We need a special correction
300      * if the offset in the low byte will overflow in the operation.
301      */
302     unsigned O = Offs & ~0xFFU;
303     if ((Offs & 0xFF) > 256 - sizeofarg (Flags)) {
304         /* We need to add the low byte also */
305         O += Offs & 0xFF;
306     }
307
308     /* Do the correction if we need one */
309     if (O != 0) {
310         g_inc (CF_INT | CF_CONST, O);
311         Offs -= O;
312     }
313
314     /* Return the new offset */
315     return Offs;
316 }
317
318
319
320 /*****************************************************************************/
321 /*                      Functions handling local labels                      */
322 /*****************************************************************************/
323
324
325
326 void g_defcodelabel (unsigned label)
327 /* Define a local code label */
328 {
329     CS_AddLabel (CS->Code, LocalLabelName (label));
330 }
331
332
333
334 void g_defdatalabel (unsigned label)
335 /* Define a local data label */
336 {
337     AddDataLine ("%s:", LocalLabelName (label));
338 }
339
340
341
342 /*****************************************************************************/
343 /*                     Functions handling global labels                      */
344 /*****************************************************************************/
345
346
347
348 void g_defgloblabel (const char* Name)
349 /* Define a global label with the given name */
350 {
351     /* Global labels are always data labels */
352     AddDataLine ("_%s:", Name);
353 }
354
355
356
357 void g_defexport (const char* Name, int ZP)
358 /* Export the given label */
359 {
360     if (ZP) {
361         AddTextLine ("\t.exportzp\t_%s", Name);
362     } else {
363         AddTextLine ("\t.export\t\t_%s", Name);
364     }
365 }
366
367
368
369 void g_defimport (const char* Name, int ZP)
370 /* Import the given label */
371 {
372     if (ZP) {
373         AddTextLine ("\t.importzp\t_%s", Name);
374     } else {
375         AddTextLine ("\t.import\t\t_%s", Name);
376     }
377 }
378
379
380
381 /*****************************************************************************/
382 /*                   Load functions for various registers                    */
383 /*****************************************************************************/
384
385
386
387 static void ldaconst (unsigned val)
388 /* Load a with a constant */
389 {
390     AddCodeLine ("lda #$%02X", val & 0xFF);
391 }
392
393
394
395 static void ldxconst (unsigned val)
396 /* Load x with a constant */
397 {
398     AddCodeLine ("ldx #$%02X", val & 0xFF);
399 }
400
401
402
403 static void ldyconst (unsigned val)
404 /* Load y with a constant */
405 {
406     AddCodeLine ("ldy #$%02X", val & 0xFF);
407 }
408
409
410
411 /*****************************************************************************/
412 /*                          Function entry and exit                          */
413 /*****************************************************************************/
414
415
416
417 /* Remember the argument size of a function. The variable is set by g_enter
418  * and used by g_leave. If the functions gets its argument size by the caller
419  * (variable param list or function without prototype), g_enter will set the
420  * value to -1.
421  */
422 static int funcargs;
423
424
425 void g_enter (unsigned flags, unsigned argsize)
426 /* Function prologue */
427 {
428     if ((flags & CF_FIXARGC) != 0) {
429         /* Just remember the argument size for the leave */
430         funcargs = argsize;
431     } else {
432         funcargs = -1;
433         AddCodeLine ("jsr enter");
434     }
435 }
436
437
438
439 void g_leave (void)
440 /* Function epilogue */
441 {
442     /* How many bytes of locals do we have to drop? */
443     int k = -oursp;
444
445     /* If we didn't have a variable argument list, don't call leave */
446     if (funcargs >= 0) {
447
448         /* Drop stackframe if needed */
449         k += funcargs;
450         if (k > 0) {
451             if (k <= 8) {
452             AddCodeLine ("jsr incsp%d", k);
453             } else {
454                 CheckLocalOffs (k);
455                 ldyconst (k);
456                 AddCodeLine ("jsr addysp");
457             }
458         }
459
460     } else {
461
462         if (k == 0) {
463             /* Nothing to drop */
464             AddCodeLine ("jsr leave");
465         } else {
466             /* We've a stack frame to drop */
467             ldyconst (k);
468             AddCodeLine ("jsr leavey");
469         }
470     }
471
472     /* Add the final rts */
473     AddCodeLine ("rts");
474 }
475
476
477
478 /*****************************************************************************/
479 /*                            Register variables                             */
480 /*****************************************************************************/
481
482
483
484 void g_save_regvars (int RegOffs, unsigned Bytes)
485 /* Save register variables */
486 {
487     /* Don't loop for up to two bytes */
488     if (Bytes == 1) {
489
490         AddCodeLine ("lda regbank%+d", RegOffs);
491         AddCodeLine ("jsr pusha");
492
493     } else if (Bytes == 2) {
494
495         AddCodeLine ("lda regbank%+d", RegOffs);
496         AddCodeLine ("ldx regbank%+d", RegOffs+1);
497         AddCodeLine ("jsr pushax");
498
499     } else {
500
501         /* More than two bytes - loop */
502         unsigned Label = GetLocalLabel ();
503         g_space (Bytes);
504         ldyconst (Bytes - 1);
505         ldxconst (Bytes);
506         g_defcodelabel (Label);
507         AddCodeLine ("lda regbank%+d,x", RegOffs-1);
508         AddCodeLine ("sta (sp),y");
509         AddCodeLine ("dey");
510         AddCodeLine ("dex");
511         AddCodeLine ("bne %s", LocalLabelName (Label));
512
513     }
514
515     /* We pushed stuff, correct the stack pointer */
516     oursp -= Bytes;
517 }
518
519
520
521 void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
522 /* Restore register variables */
523 {
524     /* Calculate the actual stack offset and check it */
525     StackOffs -= oursp;
526     CheckLocalOffs (StackOffs);
527
528     /* Don't loop for up to two bytes */
529     if (Bytes == 1) {
530
531         ldyconst (StackOffs);
532         AddCodeLine ("lda (sp),y");
533         AddCodeLine ("sta regbank%+d", RegOffs);
534
535     } else if (Bytes == 2) {
536
537         ldyconst (StackOffs);
538         AddCodeLine ("lda (sp),y");
539         AddCodeLine ("sta regbank%+d", RegOffs);
540         AddCodeLine ("iny");
541         AddCodeLine ("lda (sp),y");
542         AddCodeLine ("sta regbank%+d", RegOffs+1);
543
544     } else {
545
546         /* More than two bytes - loop */
547         unsigned Label = GetLocalLabel ();
548         ldyconst (StackOffs+Bytes-1);
549         ldxconst (Bytes);
550         g_defcodelabel (Label);
551         AddCodeLine ("lda (sp),y");
552         AddCodeLine ("sta regbank%+d,x", RegOffs-1);
553         AddCodeLine ("dey");
554         AddCodeLine ("dex");
555         AddCodeLine ("bne %s", LocalLabelName (Label));
556
557     }
558 }
559
560
561
562 /*****************************************************************************/
563 /*                           Fetching memory cells                           */
564 /*****************************************************************************/
565
566
567
568 void g_getimmed (unsigned Flags, unsigned long Val, unsigned Offs)
569 /* Load a constant into the primary register */
570 {
571     unsigned char B1, B2, B3, B4;
572     unsigned      Done;
573
574
575     if ((Flags & CF_CONST) != 0) {
576
577         /* Numeric constant */
578         switch (Flags & CF_TYPE) {
579
580             case CF_CHAR:
581                 if ((Flags & CF_FORCECHAR) != 0) {
582                     ldaconst (Val);
583                     break;
584                 }
585                 /* FALL THROUGH */
586             case CF_INT:
587                 ldxconst ((Val >> 8) & 0xFF);
588                 ldaconst (Val & 0xFF);
589                 break;
590
591             case CF_LONG:
592                 /* Split the value into 4 bytes */
593                 B1 = (unsigned char) (Val >>  0);
594                 B2 = (unsigned char) (Val >>  8);
595                 B3 = (unsigned char) (Val >> 16);
596                 B4 = (unsigned char) (Val >> 24);
597
598                 /* Remember which bytes are done */
599                 Done = 0;
600
601                 /* Load the value */
602                 AddCodeLine ("ldx #$%02X", B2);
603                 Done |= 0x02;
604                 if (B2 == B3) {
605                     AddCodeLine ("stx sreg");
606                     Done |= 0x04;
607                 }
608                 if (B2 == B4) {
609                     AddCodeLine ("stx sreg+1");
610                     Done |= 0x08;
611                 }
612                 if ((Done & 0x04) == 0 && B1 != B3) {
613                     AddCodeLine ("lda #$%02X", B3);
614                     AddCodeLine ("sta sreg");
615                     Done |= 0x04;
616                 }
617                 if ((Done & 0x08) == 0 && B1 != B4) {
618                     AddCodeLine ("lda #$%02X", B4);
619                     AddCodeLine ("sta sreg+1");
620                     Done |= 0x08;
621                 }
622                 AddCodeLine ("lda #$%02X", B1);
623                 Done |= 0x01;
624                 if ((Done & 0x04) == 0) {
625                     CHECK (B1 == B3);
626                     AddCodeLine ("sta sreg");
627                 }
628                 if ((Done & 0x08) == 0) {
629                     CHECK (B1 == B4);
630                     AddCodeLine ("sta sreg+1");
631                 }
632                 break;
633
634             default:
635                 typeerror (Flags);
636                 break;
637
638         }
639
640     } else {
641
642         /* Some sort of label */
643         const char* Label = GetLabelName (Flags, Val, Offs);
644
645         /* Load the address into the primary */
646         AddCodeLine ("lda #<(%s)", Label);
647         AddCodeLine ("ldx #>(%s)", Label);
648
649     }
650 }
651
652
653
654 void g_getstatic (unsigned flags, unsigned long label, unsigned offs)
655 /* Fetch an static memory cell into the primary register */
656 {
657     /* Create the correct label name */
658     char* lbuf = GetLabelName (flags, label, offs);
659
660     /* Check the size and generate the correct load operation */
661     switch (flags & CF_TYPE) {
662
663         case CF_CHAR:
664             if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
665                 AddCodeLine ("lda %s", lbuf);   /* load A from the label */
666             } else {
667                 ldxconst (0);
668                 AddCodeLine ("lda %s", lbuf);   /* load A from the label */
669                 if (!(flags & CF_UNSIGNED)) {
670                     /* Must sign extend */
671                     unsigned L = GetLocalLabel ();
672                     AddCodeLine ("bpl %s", LocalLabelName (L));
673                     AddCodeLine ("dex");
674                     g_defcodelabel (L);
675                 }
676             }
677             break;
678
679         case CF_INT:
680             AddCodeLine ("lda %s", lbuf);
681             if (flags & CF_TEST) {
682                 AddCodeLine ("ora %s+1", lbuf);
683             } else {
684                 AddCodeLine ("ldx %s+1", lbuf);
685             }
686             break;
687
688         case CF_LONG:
689             if (flags & CF_TEST) {
690                 AddCodeLine ("lda %s+3", lbuf);
691                 AddCodeLine ("ora %s+2", lbuf);
692                 AddCodeLine ("ora %s+1", lbuf);
693                 AddCodeLine ("ora %s+0", lbuf);
694             } else {
695                 AddCodeLine ("lda %s+3", lbuf);
696                 AddCodeLine ("sta sreg+1");
697                 AddCodeLine ("lda %s+2", lbuf);
698                 AddCodeLine ("sta sreg");
699                 AddCodeLine ("ldx %s+1", lbuf);
700                 AddCodeLine ("lda %s", lbuf);
701             }
702             break;
703
704         default:
705             typeerror (flags);
706
707     }
708 }
709
710
711
712 void g_getlocal (unsigned flags, int offs)
713 /* Fetch specified local object (local var). */
714 {
715     offs -= oursp;
716     CheckLocalOffs (offs);
717     switch (flags & CF_TYPE) {
718
719         case CF_CHAR:
720             if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
721                 if (CPU == CPU_65C02 && offs == 0) {
722                     AddCodeLine ("lda (sp)");
723                 } else {
724                     ldyconst (offs);
725                     AddCodeLine ("lda (sp),y");
726                 }
727             } else {
728                 ldyconst (offs);
729                 AddCodeLine ("ldx #$00");
730                 AddCodeLine ("lda (sp),y");
731                 if ((flags & CF_UNSIGNED) == 0) {
732                     unsigned L = GetLocalLabel();
733                     AddCodeLine ("bpl %s", LocalLabelName (L));
734                     AddCodeLine ("dex");
735                     g_defcodelabel (L);
736                 }
737             }
738             break;
739
740         case CF_INT:
741             CheckLocalOffs (offs + 1);
742             if (flags & CF_TEST) {
743                 ldyconst (offs + 1);
744                 AddCodeLine ("lda (sp),y");
745                 AddCodeLine ("dey");
746                 AddCodeLine ("ora (sp),y");
747             } else {
748                 if (CodeSizeFactor > 180) {
749                     ldyconst (offs + 1);
750                     AddCodeLine ("lda (sp),y");
751                     AddCodeLine ("tax");
752                     AddCodeLine ("dey");
753                     AddCodeLine ("lda (sp),y");
754                 } else {
755                     if (offs) {
756                         ldyconst (offs+1);
757                         AddCodeLine ("jsr ldaxysp");
758                     } else {
759                         AddCodeLine ("jsr ldax0sp");
760                     }
761                 }
762             }
763             break;
764
765         case CF_LONG:
766             if (offs) {
767                 ldyconst (offs+3);
768                 AddCodeLine ("jsr ldeaxysp");
769             } else {
770                 AddCodeLine ("jsr ldeax0sp");
771             }
772             break;
773
774         default:
775             typeerror (flags);
776     }
777 }
778
779
780
781 void g_getind (unsigned flags, unsigned offs)
782 /* Fetch the specified object type indirect through the primary register
783  * into the primary register
784  */
785 {
786     /* If the offset is greater than 255, add the part that is > 255 to
787      * the primary. This way we get an easy addition and use the low byte
788      * as the offset
789      */
790     offs = MakeByteOffs (flags, offs);
791
792     /* Handle the indirect fetch */
793     switch (flags & CF_TYPE) {
794
795         case CF_CHAR:
796             /* Character sized */
797             if (flags & CF_UNSIGNED) {
798                 ldyconst (offs);
799                 AddCodeLine ("jsr ldauidx");
800             } else {
801                 ldyconst (offs);
802                 AddCodeLine ("jsr ldaidx");
803             }
804             break;
805
806         case CF_INT:
807             if (flags & CF_TEST) {
808                 ldyconst (offs);
809                 AddCodeLine ("sta ptr1");
810                 AddCodeLine ("stx ptr1+1");
811                 AddCodeLine ("lda (ptr1),y");
812                 AddCodeLine ("iny");
813                 AddCodeLine ("ora (ptr1),y");
814             } else {
815                 if (offs == 0) {
816                     AddCodeLine ("jsr ldaxi");
817                 } else {
818                     ldyconst (offs+1);
819                     AddCodeLine ("jsr ldaxidx");
820                 }
821             }
822             break;
823
824         case CF_LONG:
825             if (offs == 0) {
826                 AddCodeLine ("jsr ldeaxi");
827             } else {
828                 ldyconst (offs+3);
829                 AddCodeLine ("jsr ldeaxidx");
830             }
831             if (flags & CF_TEST) {
832                 AddCodeLine ("jsr tsteax");
833             }
834             break;
835
836         default:
837             typeerror (flags);
838
839     }
840 }
841
842
843
844 void g_leasp (int offs)
845 /* Fetch the address of the specified symbol into the primary register */
846 {
847     /* Calculate the offset relative to sp */
848     offs -= oursp;
849
850     /* For value 0 we do direct code */
851     if (offs == 0) {
852         AddCodeLine ("lda sp");
853         AddCodeLine ("ldx sp+1");
854     } else {
855         if (CodeSizeFactor < 300) {
856             ldaconst (offs);                    /* Load A with offset value */
857             AddCodeLine ("jsr leaasp"); /* Load effective address */
858         } else {
859             unsigned L = GetLocalLabel ();
860             if (CPU == CPU_65C02 && offs == 1) {
861                 AddCodeLine ("lda sp");
862                 AddCodeLine ("ldx sp+1");
863                 AddCodeLine ("ina");
864                 AddCodeLine ("bne %s", LocalLabelName (L));
865                 AddCodeLine ("inx");
866             } else {
867                 ldaconst (offs);
868                 AddCodeLine ("clc");
869                 AddCodeLine ("ldx sp+1");
870                 AddCodeLine ("adc sp");
871                 AddCodeLine ("bcc %s", LocalLabelName (L));
872                 AddCodeLine ("inx");
873             }
874             g_defcodelabel (L);
875         }
876     }
877 }
878
879
880
881 void g_leavariadic (int Offs)
882 /* Fetch the address of a parameter in a variadic function into the primary
883  * register
884  */
885 {
886     unsigned ArgSizeOffs;
887
888     /* Calculate the offset relative to sp */
889     Offs -= oursp;
890
891     /* Get the offset of the parameter which is stored at sp+0 on function
892      * entry and check if this offset is reachable with a byte offset.
893      */
894     CHECK (oursp <= 0);
895     ArgSizeOffs = -oursp;
896     CheckLocalOffs (ArgSizeOffs);
897
898     /* Get the size of all parameters. */
899     if (ArgSizeOffs == 0 && CPU == CPU_65C02) {
900         AddCodeLine ("lda (sp)");
901     } else {
902         ldyconst (ArgSizeOffs);
903         AddCodeLine ("lda (sp),y");
904     }
905
906     /* Add the value of the stackpointer */
907     if (CodeSizeFactor > 250) {
908         unsigned L = GetLocalLabel();
909         AddCodeLine ("ldx sp+1");
910         AddCodeLine ("clc");
911         AddCodeLine ("adc sp");
912         AddCodeLine ("bcc %s", LocalLabelName (L));
913         AddCodeLine ("inx");
914         g_defcodelabel (L);
915     } else {
916         AddCodeLine ("jsr leaasp");
917     }
918
919     /* Add the offset to the primary */
920     if (Offs > 0) {
921         g_inc (CF_INT | CF_CONST, Offs);
922     } else if (Offs < 0) {
923         g_dec (CF_INT | CF_CONST, -Offs);
924     }
925 }
926
927
928
929 /*****************************************************************************/
930 /*                             Store into memory                             */
931 /*****************************************************************************/
932
933
934
935 void g_putstatic (unsigned flags, unsigned long label, unsigned offs)
936 /* Store the primary register into the specified static memory cell */
937 {
938     /* Create the correct label name */
939     char* lbuf = GetLabelName (flags, label, offs);
940
941     /* Check the size and generate the correct store operation */
942     switch (flags & CF_TYPE) {
943
944         case CF_CHAR:
945             AddCodeLine ("sta %s", lbuf);
946             break;
947
948         case CF_INT:
949             AddCodeLine ("sta %s", lbuf);
950             AddCodeLine ("stx %s+1", lbuf);
951             break;
952
953         case CF_LONG:
954             AddCodeLine ("sta %s", lbuf);
955             AddCodeLine ("stx %s+1", lbuf);
956             AddCodeLine ("ldy sreg");
957             AddCodeLine ("sty %s+2", lbuf);
958             AddCodeLine ("ldy sreg+1");
959             AddCodeLine ("sty %s+3", lbuf);
960             break;
961
962         default:
963             typeerror (flags);
964
965     }
966 }
967
968
969
970 void g_putlocal (unsigned Flags, int Offs, long Val)
971 /* Put data into local object. */
972 {
973     Offs -= oursp;
974     CheckLocalOffs (Offs);
975     switch (Flags & CF_TYPE) {
976
977         case CF_CHAR:
978             if (Flags & CF_CONST) {
979                 AddCodeLine ("lda #$%02X", (unsigned char) Val);
980             }
981             if (CPU == CPU_65C02 && Offs == 0) {
982                 AddCodeLine ("sta (sp)");
983             } else {
984                 ldyconst (Offs);
985                 AddCodeLine ("sta (sp),y");
986             }
987             break;
988
989         case CF_INT:
990             if (Flags & CF_CONST) {
991                 ldyconst (Offs+1);
992                 AddCodeLine ("lda #$%02X", (unsigned char) (Val >> 8));
993                 AddCodeLine ("sta (sp),y");
994                 if ((Flags & CF_NOKEEP) == 0) {
995                     /* Place high byte into X */
996                     AddCodeLine ("tax");
997                 }
998                 if (CPU == CPU_65C02 && Offs == 0) {
999                     AddCodeLine ("lda #$%02X", (unsigned char) Val);
1000                     AddCodeLine ("sta (sp)");
1001                 } else {
1002                     if ((Val & 0xFF) == Offs+1) {
1003                         /* The value we need is already in Y */
1004                         AddCodeLine ("tya");
1005                         AddCodeLine ("dey");
1006                     } else {
1007                         AddCodeLine ("dey");
1008                         AddCodeLine ("lda #$%02X", (unsigned char) Val);
1009                     }
1010                     AddCodeLine ("sta (sp),y");
1011                 }
1012             } else {
1013                 if ((Flags & CF_NOKEEP) == 0 || CodeSizeFactor < 160) {
1014                     ldyconst (Offs);
1015                     AddCodeLine ("jsr staxysp");
1016                 } else {
1017                     if (CPU == CPU_65C02 && Offs == 0) {
1018                         AddCodeLine ("sta (sp)");
1019                         ldyconst (1);
1020                         AddCodeLine ("txa");
1021                         AddCodeLine ("sta (sp),y");
1022                     } else {
1023                         ldyconst (Offs);
1024                         AddCodeLine ("sta (sp),y");
1025                         AddCodeLine ("iny");
1026                         AddCodeLine ("txa");
1027                         AddCodeLine ("sta (sp),y");
1028                     }
1029                 }
1030             }
1031             break;
1032
1033         case CF_LONG:
1034             if (Flags & CF_CONST) {
1035                 g_getimmed (Flags, Val, 0);
1036             }
1037             if (Offs) {
1038                 ldyconst (Offs);
1039                 AddCodeLine ("jsr steaxysp");
1040             } else {
1041                 AddCodeLine ("jsr steax0sp");
1042             }
1043             break;
1044
1045         default:
1046             typeerror (Flags);
1047
1048     }
1049 }
1050
1051
1052
1053 void g_putind (unsigned Flags, unsigned Offs)
1054 /* Store the specified object type in the primary register at the address
1055  * on the top of the stack
1056  */
1057 {
1058     /* We can handle offsets below $100 directly, larger offsets must be added
1059      * to the address. Since a/x is in use, best code is achieved by adding
1060      * just the high byte. Be sure to check if the low byte will overflow while
1061      * while storing.
1062      */
1063     if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
1064
1065         /* Overflow - we need to add the low byte also */
1066         AddCodeLine ("ldy #$00");
1067         AddCodeLine ("clc");
1068         AddCodeLine ("pha");
1069         AddCodeLine ("lda #$%02X", Offs & 0xFF);
1070         AddCodeLine ("adc (sp),y");
1071         AddCodeLine ("sta (sp),y");
1072         AddCodeLine ("iny");
1073         AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1074         AddCodeLine ("adc (sp),y");
1075         AddCodeLine ("sta (sp),y");
1076         AddCodeLine ("pla");
1077
1078         /* Complete address is on stack, new offset is zero */
1079         Offs = 0;
1080
1081     } else if ((Offs & 0xFF00) != 0) {
1082
1083         /* We can just add the high byte */
1084         AddCodeLine ("ldy #$01");
1085         AddCodeLine ("clc");
1086         AddCodeLine ("pha");
1087         AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1088         AddCodeLine ("adc (sp),y");
1089         AddCodeLine ("sta (sp),y");
1090         AddCodeLine ("pla");
1091
1092         /* Offset is now just the low byte */
1093         Offs &= 0x00FF;
1094     }
1095
1096     /* Check the size and determine operation */
1097     switch (Flags & CF_TYPE) {
1098
1099         case CF_CHAR:
1100             ldyconst (Offs);
1101             AddCodeLine ("jsr staspidx");
1102             break;
1103
1104         case CF_INT:
1105             ldyconst (Offs);
1106             AddCodeLine ("jsr staxspidx");
1107             break;
1108
1109         case CF_LONG:
1110             ldyconst (Offs);
1111             AddCodeLine ("jsr steaxspidx");
1112             break;
1113
1114         default:
1115             typeerror (Flags);
1116
1117     }
1118
1119     /* Pop the argument which is always a pointer */
1120     pop (CF_PTR);
1121 }
1122
1123
1124
1125 /*****************************************************************************/
1126 /*                    type conversion and similiar stuff                     */
1127 /*****************************************************************************/
1128
1129
1130
1131 void g_toslong (unsigned flags)
1132 /* Make sure, the value on TOS is a long. Convert if necessary */
1133 {
1134     switch (flags & CF_TYPE) {
1135
1136         case CF_CHAR:
1137         case CF_INT:
1138             if (flags & CF_UNSIGNED) {
1139                 AddCodeLine ("jsr tosulong");
1140             } else {
1141                 AddCodeLine ("jsr toslong");
1142             }
1143             push (CF_INT);
1144             break;
1145
1146         case CF_LONG:
1147             break;
1148
1149         default:
1150             typeerror (flags);
1151     }
1152 }
1153
1154
1155
1156 void g_tosint (unsigned flags)
1157 /* Make sure, the value on TOS is an int. Convert if necessary */
1158 {
1159     switch (flags & CF_TYPE) {
1160
1161         case CF_CHAR:
1162         case CF_INT:
1163             break;
1164
1165         case CF_LONG:
1166             AddCodeLine ("jsr tosint");
1167             pop (CF_INT);
1168             break;
1169
1170         default:
1171             typeerror (flags);
1172     }
1173 }
1174
1175
1176
1177 void g_reglong (unsigned flags)
1178 /* Make sure, the value in the primary register a long. Convert if necessary */
1179 {
1180     switch (flags & CF_TYPE) {
1181
1182         case CF_CHAR:
1183         case CF_INT:
1184             if (flags & CF_UNSIGNED) {
1185                 if (CodeSizeFactor >= 200) {
1186                     ldyconst (0);
1187                     AddCodeLine ("sty sreg");
1188                     AddCodeLine ("sty sreg+1");
1189                 } else {
1190                     AddCodeLine ("jsr axulong");
1191                 }
1192             } else {
1193                 AddCodeLine ("jsr axlong");
1194             }
1195             break;
1196
1197         case CF_LONG:
1198             break;
1199
1200         default:
1201             typeerror (flags);
1202     }
1203 }
1204
1205
1206
1207 unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1208 /* Adjust the integer operands before doing a binary operation. lhs is a flags
1209  * value, that corresponds to the value on TOS, rhs corresponds to the value
1210  * in (e)ax. The return value is the the flags value for the resulting type.
1211  */
1212 {
1213     unsigned ltype, rtype;
1214     unsigned result;
1215
1216     /* Get the type spec from the flags */
1217     ltype = lhs & CF_TYPE;
1218     rtype = rhs & CF_TYPE;
1219
1220     /* Check if a conversion is needed */
1221     if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1222         /* We must promote the primary register to long */
1223         g_reglong (rhs);
1224         /* Get the new rhs type */
1225         rhs = (rhs & ~CF_TYPE) | CF_LONG;
1226         rtype = CF_LONG;
1227     } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1228         /* We must promote the lhs to long */
1229         if (lhs & CF_REG) {
1230             g_reglong (lhs);
1231         } else {
1232             g_toslong (lhs);
1233         }
1234         /* Get the new rhs type */
1235         lhs = (lhs & ~CF_TYPE) | CF_LONG;
1236         ltype = CF_LONG;
1237     }
1238
1239     /* Determine the result type for the operation:
1240      *  - The result is const if both operands are const.
1241      *  - The result is unsigned if one of the operands is unsigned.
1242      *  - The result is long if one of the operands is long.
1243      *  - Otherwise the result is int sized.
1244      */
1245     result = (lhs & CF_CONST) & (rhs & CF_CONST);
1246     result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1247     if (rtype == CF_LONG || ltype == CF_LONG) {
1248         result |= CF_LONG;
1249     } else {
1250         result |= CF_INT;
1251     }
1252     return result;
1253 }
1254
1255
1256
1257 unsigned g_typecast (unsigned lhs, unsigned rhs)
1258 /* Cast the value in the primary register to the operand size that is flagged
1259  * by the lhs value. Return the result value.
1260  */
1261 {
1262     unsigned ltype, rtype;
1263
1264     /* Get the type spec from the flags */
1265     ltype = lhs & CF_TYPE;
1266     rtype = rhs & CF_TYPE;
1267
1268     /* Check if a conversion is needed */
1269     if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1270         /* We must promote the primary register to long */
1271         g_reglong (rhs);
1272     }
1273
1274     /* Do not need any other action. If the left type is int, and the primary
1275      * register is long, it will be automagically truncated. If the right hand
1276      * side is const, it is not located in the primary register and handled by
1277      * the expression parser code.
1278      */
1279
1280     /* Result is const if the right hand side was const */
1281     lhs |= (rhs & CF_CONST);
1282
1283     /* The resulting type is that of the left hand side (that's why you called
1284      * this function :-)
1285      */
1286     return lhs;
1287 }
1288
1289
1290
1291 void g_scale (unsigned flags, long val)
1292 /* Scale the value in the primary register by the given value. If val is positive,
1293  * scale up, is val is negative, scale down. This function is used to scale
1294  * the operands or results of pointer arithmetic by the size of the type, the
1295  * pointer points to.
1296  */
1297 {
1298     int p2;
1299
1300     /* Value may not be zero */
1301     if (val == 0) {
1302         Internal ("Data type has no size");
1303     } else if (val > 0) {
1304
1305         /* Scale up */
1306         if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
1307
1308             /* Factor is 2, 4, 8 and 16, use special function */
1309             switch (flags & CF_TYPE) {
1310
1311                 case CF_CHAR:
1312                     if (flags & CF_FORCECHAR) {
1313                         while (p2--) {
1314                             AddCodeLine ("asl a");
1315                         }
1316                         break;
1317                     }
1318                     /* FALLTHROUGH */
1319
1320                 case CF_INT:
1321                     if (CodeSizeFactor >= (p2+1)*130U) {
1322                         AddCodeLine ("stx tmp1");
1323                         while (p2--) {
1324                             AddCodeLine ("asl a");
1325                             AddCodeLine ("rol tmp1");
1326                         }
1327                         AddCodeLine ("ldx tmp1");
1328                     } else {
1329                         if (flags & CF_UNSIGNED) {
1330                             AddCodeLine ("jsr shlax%d", p2);
1331                         } else {
1332                             AddCodeLine ("jsr aslax%d", p2);
1333                         }
1334                     }
1335                     break;
1336
1337                 case CF_LONG:
1338                     if (flags & CF_UNSIGNED) {
1339                         AddCodeLine ("jsr shleax%d", p2);
1340                     } else {
1341                         AddCodeLine ("jsr asleax%d", p2);
1342                     }
1343                     break;
1344
1345                 default:
1346                     typeerror (flags);
1347
1348             }
1349
1350         } else if (val != 1) {
1351
1352             /* Use a multiplication instead */
1353             g_mul (flags | CF_CONST, val);
1354
1355         }
1356
1357     } else {
1358
1359         /* Scale down */
1360         val = -val;
1361         if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
1362
1363             /* Factor is 2, 4, 8 and 16 use special function */
1364             switch (flags & CF_TYPE) {
1365
1366                 case CF_CHAR:
1367                     if (flags & CF_FORCECHAR) {
1368                         if (flags & CF_UNSIGNED) {
1369                             while (p2--) {
1370                                 AddCodeLine ("lsr a");
1371                             }
1372                             break;
1373                         } else if (p2 <= 2) {
1374                             AddCodeLine ("cmp #$80");
1375                             AddCodeLine ("ror a");
1376                             break;
1377                         }
1378                     }
1379                     /* FALLTHROUGH */
1380
1381                 case CF_INT:
1382                     if (flags & CF_UNSIGNED) {
1383                         if (CodeSizeFactor >= (p2+1)*130U) {
1384                             AddCodeLine ("stx tmp1");
1385                             while (p2--) {
1386                                 AddCodeLine ("lsr tmp1");
1387                                 AddCodeLine ("ror a");
1388                             }
1389                             AddCodeLine ("ldx tmp1");
1390                         } else {
1391                             AddCodeLine ("jsr lsrax%d", p2);
1392                         }
1393                     } else {
1394                         if (CodeSizeFactor >= (p2+1)*150U) {
1395                             AddCodeLine ("stx tmp1");
1396                             while (p2--) {
1397                                 AddCodeLine ("cpx #$80");
1398                                 AddCodeLine ("ror tmp1");
1399                                 AddCodeLine ("ror a");
1400                             }
1401                             AddCodeLine ("ldx tmp1");
1402                         } else {
1403                             AddCodeLine ("jsr asrax%d", p2);
1404                         }
1405                     }
1406                     break;
1407
1408                 case CF_LONG:
1409                     if (flags & CF_UNSIGNED) {
1410                         AddCodeLine ("jsr lsreax%d", p2);
1411                     } else {
1412                         AddCodeLine ("jsr asreax%d", p2);
1413                     }
1414                     break;
1415
1416                 default:
1417                     typeerror (flags);
1418
1419             }
1420
1421         } else if (val != 1) {
1422
1423             /* Use a division instead */
1424             g_div (flags | CF_CONST, val);
1425
1426         }
1427     }
1428 }
1429
1430
1431
1432 /*****************************************************************************/
1433 /*              Adds and subs of variables fix a fixed address               */
1434 /*****************************************************************************/
1435
1436
1437
1438 void g_addlocal (unsigned flags, int offs)
1439 /* Add a local variable to ax */
1440 {
1441     unsigned L;
1442
1443     /* Correct the offset and check it */
1444     offs -= oursp;
1445     CheckLocalOffs (offs);
1446
1447     switch (flags & CF_TYPE) {
1448
1449         case CF_CHAR:
1450             L = GetLocalLabel();
1451             AddCodeLine ("ldy #$%02X", offs & 0xFF);
1452             AddCodeLine ("clc");
1453             AddCodeLine ("adc (sp),y");
1454             AddCodeLine ("bcc %s", LocalLabelName (L));
1455             AddCodeLine ("inx");
1456             g_defcodelabel (L);
1457             break;
1458
1459         case CF_INT:
1460             AddCodeLine ("ldy #$%02X", offs & 0xFF);
1461             AddCodeLine ("clc");
1462             AddCodeLine ("adc (sp),y");
1463             AddCodeLine ("pha");
1464             AddCodeLine ("txa");
1465             AddCodeLine ("iny");
1466             AddCodeLine ("adc (sp),y");
1467             AddCodeLine ("tax");
1468             AddCodeLine ("pla");
1469             break;
1470
1471         case CF_LONG:
1472             /* Do it the old way */
1473             g_push (flags, 0);
1474             g_getlocal (flags, offs);
1475             g_add (flags, 0);
1476             break;
1477
1478         default:
1479             typeerror (flags);
1480
1481     }
1482 }
1483
1484
1485
1486 void g_addstatic (unsigned flags, unsigned long label, unsigned offs)
1487 /* Add a static variable to ax */
1488 {
1489     unsigned L;
1490
1491     /* Create the correct label name */
1492     char* lbuf = GetLabelName (flags, label, offs);
1493
1494     switch (flags & CF_TYPE) {
1495
1496         case CF_CHAR:
1497             L = GetLocalLabel();
1498             AddCodeLine ("clc");
1499             AddCodeLine ("adc %s", lbuf);
1500             AddCodeLine ("bcc %s", LocalLabelName (L));
1501             AddCodeLine ("inx");
1502             g_defcodelabel (L);
1503             break;
1504
1505         case CF_INT:
1506             AddCodeLine ("clc");
1507             AddCodeLine ("adc %s", lbuf);
1508             AddCodeLine ("tay");
1509             AddCodeLine ("txa");
1510             AddCodeLine ("adc %s+1", lbuf);
1511             AddCodeLine ("tax");
1512             AddCodeLine ("tya");
1513             break;
1514
1515         case CF_LONG:
1516             /* Do it the old way */
1517             g_push (flags, 0);
1518             g_getstatic (flags, label, offs);
1519             g_add (flags, 0);
1520             break;
1521
1522         default:
1523             typeerror (flags);
1524
1525     }
1526 }
1527
1528
1529
1530 /*****************************************************************************/
1531 /*             Compares of ax with a variable with fixed address             */
1532 /*****************************************************************************/
1533
1534
1535
1536 void g_cmplocal (unsigned flags, int offs)
1537 /* Compare a local variable to ax */
1538 {
1539     Internal ("g_cmplocal not implemented");
1540 }
1541
1542
1543
1544 void g_cmpstatic (unsigned flags, unsigned label, unsigned offs)
1545 /* Compare a static variable to ax */
1546 {
1547     Internal ("g_cmpstatic not implemented");
1548 }
1549
1550
1551
1552 /*****************************************************************************/
1553 /*                           Special op= functions                           */
1554 /*****************************************************************************/
1555
1556
1557
1558 void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
1559                     unsigned long val)
1560 /* Emit += for a static variable */
1561 {
1562     /* Create the correct label name */
1563     char* lbuf = GetLabelName (flags, label, offs);
1564
1565     /* Check the size and determine operation */
1566     switch (flags & CF_TYPE) {
1567
1568         case CF_CHAR:
1569             if (flags & CF_FORCECHAR) {
1570                 AddCodeLine ("ldx #$00");
1571                 if (flags & CF_CONST) {
1572                     if (val == 1) {
1573                         AddCodeLine ("inc %s", lbuf);
1574                         AddCodeLine ("lda %s", lbuf);
1575                     } else {
1576                         AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1577                         AddCodeLine ("clc");
1578                         AddCodeLine ("adc %s", lbuf);
1579                         AddCodeLine ("sta %s", lbuf);
1580                     }
1581                 } else {
1582                     AddCodeLine ("clc");
1583                     AddCodeLine ("adc %s", lbuf);
1584                     AddCodeLine ("sta %s", lbuf);
1585                 }
1586                 if ((flags & CF_UNSIGNED) == 0) {
1587                     unsigned L = GetLocalLabel();
1588                     AddCodeLine ("bpl %s", LocalLabelName (L));
1589                     AddCodeLine ("dex");
1590                     g_defcodelabel (L);
1591                 }
1592                 break;
1593             }
1594             /* FALLTHROUGH */
1595
1596         case CF_INT:
1597             if (flags & CF_CONST) {
1598                 if (val == 1) {
1599                     unsigned L = GetLocalLabel ();
1600                     AddCodeLine ("inc %s", lbuf);
1601                     AddCodeLine ("bne %s", LocalLabelName (L));
1602                     AddCodeLine ("inc %s+1", lbuf);
1603                     g_defcodelabel (L);
1604                     AddCodeLine ("lda %s", lbuf);               /* Hmmm... */
1605                     AddCodeLine ("ldx %s+1", lbuf);
1606                 } else {
1607                     AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1608                     AddCodeLine ("clc");
1609                     AddCodeLine ("adc %s", lbuf);
1610                     AddCodeLine ("sta %s", lbuf);
1611                     if (val < 0x100) {
1612                         unsigned L = GetLocalLabel ();
1613                         AddCodeLine ("bcc %s", LocalLabelName (L));
1614                         AddCodeLine ("inc %s+1", lbuf);
1615                         g_defcodelabel (L);
1616                         AddCodeLine ("ldx %s+1", lbuf);
1617                     } else {
1618                         AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1619                         AddCodeLine ("adc %s+1", lbuf);
1620                         AddCodeLine ("sta %s+1", lbuf);
1621                         AddCodeLine ("tax");
1622                         AddCodeLine ("lda %s", lbuf);
1623                     }
1624                 }
1625             } else {
1626                 AddCodeLine ("clc");
1627                 AddCodeLine ("adc %s", lbuf);
1628                 AddCodeLine ("sta %s", lbuf);
1629                 AddCodeLine ("txa");
1630                 AddCodeLine ("adc %s+1", lbuf);
1631                 AddCodeLine ("sta %s+1", lbuf);
1632                 AddCodeLine ("tax");
1633                 AddCodeLine ("lda %s", lbuf);
1634             }
1635             break;
1636
1637         case CF_LONG:
1638             if (flags & CF_CONST) {
1639                 if (val < 0x100) {
1640                     AddCodeLine ("ldy #<(%s)", lbuf);
1641                     AddCodeLine ("sty ptr1");
1642                     AddCodeLine ("ldy #>(%s+1)", lbuf);
1643                     if (val == 1) {
1644                         AddCodeLine ("jsr laddeq1");
1645                     } else {
1646                         AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1647                         AddCodeLine ("jsr laddeqa");
1648                     }
1649                 } else {
1650                     g_getstatic (flags, label, offs);
1651                     g_inc (flags, val);
1652                     g_putstatic (flags, label, offs);
1653                 }
1654             } else {
1655                 AddCodeLine ("ldy #<(%s)", lbuf);
1656                 AddCodeLine ("sty ptr1");
1657                 AddCodeLine ("ldy #>(%s+1)", lbuf);
1658                 AddCodeLine ("jsr laddeq");
1659             }
1660             break;
1661
1662         default:
1663             typeerror (flags);
1664     }
1665 }
1666
1667
1668
1669 void g_addeqlocal (unsigned flags, int offs, unsigned long val)
1670 /* Emit += for a local variable */
1671 {
1672     /* Calculate the true offset, check it, load it into Y */
1673     offs -= oursp;
1674     CheckLocalOffs (offs);
1675
1676     /* Check the size and determine operation */
1677     switch (flags & CF_TYPE) {
1678
1679         case CF_CHAR:
1680             if (flags & CF_FORCECHAR) {
1681                 ldyconst (offs);
1682                 AddCodeLine ("ldx #$00");
1683                 if (flags & CF_CONST) {
1684                     AddCodeLine ("clc");
1685                     AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1686                     AddCodeLine ("adc (sp),y");
1687                     AddCodeLine ("sta (sp),y");
1688                 } else {
1689                     AddCodeLine ("clc");
1690                     AddCodeLine ("adc (sp),y");
1691                     AddCodeLine ("sta (sp),y");
1692                 }
1693                 if ((flags & CF_UNSIGNED) == 0) {
1694                     unsigned L = GetLocalLabel();
1695                     AddCodeLine ("bpl %s", LocalLabelName (L));
1696                     AddCodeLine ("dex");
1697                     g_defcodelabel (L);
1698                 }
1699                 break;
1700             }
1701             /* FALLTHROUGH */
1702
1703         case CF_INT:
1704             if (flags & CF_CONST) {
1705                 g_getimmed (flags, val, 0);
1706             }
1707             ldyconst (offs);
1708             AddCodeLine ("jsr addeqysp");
1709             break;
1710
1711         case CF_LONG:
1712             if (flags & CF_CONST) {
1713                 g_getimmed (flags, val, 0);
1714             }
1715             if (offs == 0) {
1716                 AddCodeLine ("jsr laddeq0sp");
1717             } else {
1718                 ldyconst (offs);
1719                 AddCodeLine ("jsr laddeqysp");
1720             }
1721             break;
1722
1723         default:
1724             typeerror (flags);
1725     }
1726 }
1727
1728
1729
1730 void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
1731 /* Emit += for the location with address in ax */
1732 {
1733     /* If the offset is too large for a byte register, add the high byte
1734      * of the offset to the primary. Beware: We need a special correction
1735      * if the offset in the low byte will overflow in the operation.
1736      */
1737     offs = MakeByteOffs (flags, offs);
1738
1739     /* Check the size and determine operation */
1740     switch (flags & CF_TYPE) {
1741
1742         case CF_CHAR:
1743             AddCodeLine ("sta ptr1");
1744             AddCodeLine ("stx ptr1+1");
1745             AddCodeLine ("ldy #$%02X", offs);
1746             AddCodeLine ("ldx #$00");
1747             AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1748             AddCodeLine ("clc");
1749             AddCodeLine ("adc (ptr1),y");
1750             AddCodeLine ("sta (ptr1),y");
1751             break;
1752
1753         case CF_INT:
1754             if (CodeSizeFactor >= 200) {
1755                 /* Lots of code, use only if size is not important */
1756                 AddCodeLine ("sta ptr1");
1757                 AddCodeLine ("stx ptr1+1");
1758                 AddCodeLine ("ldy #$%02X", offs);
1759                 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1760                 AddCodeLine ("clc");
1761                 AddCodeLine ("adc (ptr1),y");
1762                 AddCodeLine ("sta (ptr1),y");
1763                 AddCodeLine ("pha");
1764                 AddCodeLine ("iny");
1765                 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1766                 AddCodeLine ("adc (ptr1),y");
1767                 AddCodeLine ("sta (ptr1),y");
1768                 AddCodeLine ("tax");
1769                 AddCodeLine ("pla");
1770                 break;
1771             }
1772             /* FALL THROUGH */
1773
1774         case CF_LONG:
1775             AddCodeLine ("jsr pushax");         /* Push the address */
1776             push (CF_PTR);                      /* Correct the internal sp */
1777             g_getind (flags, offs);             /* Fetch the value */
1778             g_inc (flags, val);                 /* Increment value in primary */
1779             g_putind (flags, offs);             /* Store the value back */
1780             break;
1781
1782         default:
1783             typeerror (flags);
1784     }
1785 }
1786
1787
1788
1789 void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
1790                     unsigned long val)
1791 /* Emit -= for a static variable */
1792 {
1793     /* Create the correct label name */
1794     char* lbuf = GetLabelName (flags, label, offs);
1795
1796     /* Check the size and determine operation */
1797     switch (flags & CF_TYPE) {
1798
1799         case CF_CHAR:
1800             if (flags & CF_FORCECHAR) {
1801                 AddCodeLine ("ldx #$00");
1802                 if (flags & CF_CONST) {
1803                     if (val == 1) {
1804                         AddCodeLine ("dec %s", lbuf);
1805                         AddCodeLine ("lda %s", lbuf);
1806                     } else {
1807                         AddCodeLine ("sec");
1808                         AddCodeLine ("lda %s", lbuf);
1809                         AddCodeLine ("sbc #$%02X", (int)(val & 0xFF));
1810                         AddCodeLine ("sta %s", lbuf);
1811                     }
1812                 } else {
1813                     AddCodeLine ("sec");
1814                     AddCodeLine ("sta tmp1");
1815                     AddCodeLine ("lda %s", lbuf);
1816                     AddCodeLine ("sbc tmp1");
1817                     AddCodeLine ("sta %s", lbuf);
1818                 }
1819                 if ((flags & CF_UNSIGNED) == 0) {
1820                     unsigned L = GetLocalLabel();
1821                     AddCodeLine ("bpl %s", LocalLabelName (L));
1822                     AddCodeLine ("dex");
1823                     g_defcodelabel (L);
1824                 }
1825                 break;
1826             }
1827             /* FALLTHROUGH */
1828
1829         case CF_INT:
1830             AddCodeLine ("sec");
1831             if (flags & CF_CONST) {
1832                 AddCodeLine ("lda %s", lbuf);
1833                 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1834                 AddCodeLine ("sta %s", lbuf);
1835                 if (val < 0x100) {
1836                     unsigned L = GetLocalLabel ();
1837                     AddCodeLine ("bcs %s", LocalLabelName (L));
1838                     AddCodeLine ("dec %s+1", lbuf);
1839                     g_defcodelabel (L);
1840                     AddCodeLine ("ldx %s+1", lbuf);
1841                 } else {
1842                     AddCodeLine ("lda %s+1", lbuf);
1843                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
1844                     AddCodeLine ("sta %s+1", lbuf);
1845                     AddCodeLine ("tax");
1846                     AddCodeLine ("lda %s", lbuf);
1847                 }
1848             } else {
1849                 AddCodeLine ("sta tmp1");
1850                 AddCodeLine ("lda %s", lbuf);
1851                 AddCodeLine ("sbc tmp1");
1852                 AddCodeLine ("sta %s", lbuf);
1853                 AddCodeLine ("stx tmp1");
1854                 AddCodeLine ("lda %s+1", lbuf);
1855                 AddCodeLine ("sbc tmp1");
1856                 AddCodeLine ("sta %s+1", lbuf);
1857                 AddCodeLine ("tax");
1858                 AddCodeLine ("lda %s", lbuf);
1859             }
1860             break;
1861
1862         case CF_LONG:
1863             if (flags & CF_CONST) {
1864                 if (val < 0x100) {
1865                     AddCodeLine ("ldy #<(%s)", lbuf);
1866                     AddCodeLine ("sty ptr1");
1867                     AddCodeLine ("ldy #>(%s+1)", lbuf);
1868                     if (val == 1) {
1869                         AddCodeLine ("jsr lsubeq1");
1870                     } else {
1871                         AddCodeLine ("lda #$%02X", (unsigned char)val);
1872                         AddCodeLine ("jsr lsubeqa");
1873                     }
1874                 } else {
1875                     g_getstatic (flags, label, offs);
1876                     g_dec (flags, val);
1877                     g_putstatic (flags, label, offs);
1878                 }
1879             } else {
1880                 AddCodeLine ("ldy #<(%s)", lbuf);
1881                 AddCodeLine ("sty ptr1");
1882                 AddCodeLine ("ldy #>(%s+1)", lbuf);
1883                 AddCodeLine ("jsr lsubeq");
1884             }
1885             break;
1886
1887         default:
1888             typeerror (flags);
1889     }
1890 }
1891
1892
1893
1894 void g_subeqlocal (unsigned flags, int offs, unsigned long val)
1895 /* Emit -= for a local variable */
1896 {
1897     /* Calculate the true offset, check it, load it into Y */
1898     offs -= oursp;
1899     CheckLocalOffs (offs);
1900
1901     /* Check the size and determine operation */
1902     switch (flags & CF_TYPE) {
1903
1904         case CF_CHAR:
1905             if (flags & CF_FORCECHAR) {
1906                 ldyconst (offs);
1907                 AddCodeLine ("ldx #$00");
1908                 AddCodeLine ("sec");
1909                 if (flags & CF_CONST) {
1910                     AddCodeLine ("lda (sp),y");
1911                     AddCodeLine ("sbc #$%02X", (unsigned char)val);
1912                 } else {
1913                     AddCodeLine ("sta tmp1");
1914                     AddCodeLine ("lda (sp),y");
1915                     AddCodeLine ("sbc tmp1");
1916                 }
1917                 AddCodeLine ("sta (sp),y");
1918                 if ((flags & CF_UNSIGNED) == 0) {
1919                     unsigned L = GetLocalLabel();
1920                     AddCodeLine ("bpl %s", LocalLabelName (L));
1921                     AddCodeLine ("dex");
1922                     g_defcodelabel (L);
1923                 }
1924                 break;
1925             }
1926             /* FALLTHROUGH */
1927
1928         case CF_INT:
1929             if (flags & CF_CONST) {
1930                 g_getimmed (flags, val, 0);
1931             }
1932             if (offs == 0) {
1933                 AddCodeLine ("jsr subeq0sp");
1934             } else {
1935                 ldyconst (offs);
1936                 AddCodeLine ("jsr subeqysp");
1937             }
1938             break;
1939
1940         case CF_LONG:
1941             if (flags & CF_CONST) {
1942                 g_getimmed (flags, val, 0);
1943             }
1944             if (offs == 0) {
1945                 AddCodeLine ("jsr lsubeq0sp");
1946             } else {
1947                 ldyconst (offs);
1948                 AddCodeLine ("jsr lsubeqysp");
1949             }
1950             break;
1951
1952         default:
1953             typeerror (flags);
1954     }
1955 }
1956
1957
1958
1959 void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
1960 /* Emit -= for the location with address in ax */
1961 {
1962     /* If the offset is too large for a byte register, add the high byte
1963      * of the offset to the primary. Beware: We need a special correction
1964      * if the offset in the low byte will overflow in the operation.
1965      */
1966     offs = MakeByteOffs (flags, offs);
1967
1968     /* Check the size and determine operation */
1969     switch (flags & CF_TYPE) {
1970
1971         case CF_CHAR:
1972             AddCodeLine ("sta ptr1");
1973             AddCodeLine ("stx ptr1+1");
1974             AddCodeLine ("ldy #$%02X", offs);
1975             AddCodeLine ("ldx #$00");
1976             AddCodeLine ("lda (ptr1),y");
1977             AddCodeLine ("sec");
1978             AddCodeLine ("sbc #$%02X", (unsigned char)val);
1979             AddCodeLine ("sta (ptr1),y");
1980             break;
1981
1982         case CF_INT:
1983             if (CodeSizeFactor >= 200) {
1984                 /* Lots of code, use only if size is not important */
1985                 AddCodeLine ("sta ptr1");
1986                 AddCodeLine ("stx ptr1+1");
1987                 AddCodeLine ("ldy #$%02X", offs);
1988                 AddCodeLine ("lda (ptr1),y");
1989                 AddCodeLine ("sec");
1990                 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1991                 AddCodeLine ("sta (ptr1),y");
1992                 AddCodeLine ("pha");
1993                 AddCodeLine ("iny");
1994                 AddCodeLine ("lda (ptr1),y");
1995                 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
1996                 AddCodeLine ("sta (ptr1),y");
1997                 AddCodeLine ("tax");
1998                 AddCodeLine ("pla");
1999                 break;
2000             }
2001             /* FALL THROUGH */
2002
2003         case CF_LONG:
2004             AddCodeLine ("jsr pushax");         /* Push the address */
2005             push (CF_PTR);                      /* Correct the internal sp */
2006             g_getind (flags, offs);             /* Fetch the value */
2007             g_dec (flags, val);                 /* Increment value in primary */
2008             g_putind (flags, offs);             /* Store the value back */
2009             break;
2010
2011         default:
2012             typeerror (flags);
2013     }
2014 }
2015
2016
2017
2018 /*****************************************************************************/
2019 /*                 Add a variable address to the value in ax                 */
2020 /*****************************************************************************/
2021
2022
2023
2024 void g_addaddr_local (unsigned flags, int offs)
2025 /* Add the address of a local variable to ax */
2026 {
2027     unsigned L = 0;
2028
2029     /* Add the offset */
2030     offs -= oursp;
2031     if (offs != 0) {
2032         /* We cannot address more then 256 bytes of locals anyway */
2033         L = GetLocalLabel();
2034         CheckLocalOffs (offs);
2035         AddCodeLine ("clc");
2036         AddCodeLine ("adc #$%02X", offs & 0xFF);
2037         /* Do also skip the CLC insn below */
2038         AddCodeLine ("bcc %s", LocalLabelName (L));
2039         AddCodeLine ("inx");
2040     }
2041
2042     /* Add the current stackpointer value */
2043     AddCodeLine ("clc");
2044     if (L != 0) {
2045         /* Label was used above */
2046         g_defcodelabel (L);
2047     }
2048     AddCodeLine ("adc sp");
2049     AddCodeLine ("tay");
2050     AddCodeLine ("txa");
2051     AddCodeLine ("adc sp+1");
2052     AddCodeLine ("tax");
2053     AddCodeLine ("tya");
2054 }
2055
2056
2057
2058 void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs)
2059 /* Add the address of a static variable to ax */
2060 {
2061     /* Create the correct label name */
2062     char* lbuf = GetLabelName (flags, label, offs);
2063
2064     /* Add the address to the current ax value */
2065     AddCodeLine ("clc");
2066     AddCodeLine ("adc #<(%s)", lbuf);
2067     AddCodeLine ("tay");
2068     AddCodeLine ("txa");
2069     AddCodeLine ("adc #>(%s)", lbuf);
2070     AddCodeLine ("tax");
2071     AddCodeLine ("tya");
2072 }
2073
2074
2075
2076 /*****************************************************************************/
2077 /*                                                                           */
2078 /*****************************************************************************/
2079
2080
2081
2082 void g_save (unsigned flags)
2083 /* Copy primary register to hold register. */
2084 {
2085     /* Check the size and determine operation */
2086     switch (flags & CF_TYPE) {
2087
2088         case CF_CHAR:
2089             if (flags & CF_FORCECHAR) {
2090                 AddCodeLine ("pha");
2091                 break;
2092             }
2093             /* FALLTHROUGH */
2094
2095         case CF_INT:
2096             AddCodeLine ("sta regsave");
2097             AddCodeLine ("stx regsave+1");
2098             break;
2099
2100         case CF_LONG:
2101             AddCodeLine ("jsr saveeax");
2102             break;
2103
2104         default:
2105             typeerror (flags);
2106     }
2107 }
2108
2109
2110
2111 void g_restore (unsigned flags)
2112 /* Copy hold register to primary. */
2113 {
2114     /* Check the size and determine operation */
2115     switch (flags & CF_TYPE) {
2116
2117         case CF_CHAR:
2118             if (flags & CF_FORCECHAR) {
2119                 AddCodeLine ("pla");
2120                 break;
2121             }
2122             /* FALLTHROUGH */
2123
2124         case CF_INT:
2125             AddCodeLine ("lda regsave");
2126             AddCodeLine ("ldx regsave+1");
2127             break;
2128
2129         case CF_LONG:
2130             AddCodeLine ("jsr resteax");
2131             break;
2132
2133         default:
2134             typeerror (flags);
2135     }
2136 }
2137
2138
2139
2140 void g_cmp (unsigned flags, unsigned long val)
2141 /* Immidiate compare. The primary register will not be changed, Z flag
2142  * will be set.
2143  */
2144 {
2145     unsigned L;
2146
2147     /* Check the size and determine operation */
2148     switch (flags & CF_TYPE) {
2149
2150         case CF_CHAR:
2151             if (flags & CF_FORCECHAR) {
2152                 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2153                 break;
2154             }
2155             /* FALLTHROUGH */
2156
2157         case CF_INT:
2158             L = GetLocalLabel();
2159             AddCodeLine ("cmp #$%02X", (unsigned char)val);
2160             AddCodeLine ("bne %s", LocalLabelName (L));
2161             AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
2162             g_defcodelabel (L);
2163             break;
2164
2165         case CF_LONG:
2166             Internal ("g_cmp: Long compares not implemented");
2167             break;
2168
2169         default:
2170             typeerror (flags);
2171     }
2172 }
2173
2174
2175
2176 static void oper (unsigned flags, unsigned long val, char** subs)
2177 /* Encode a binary operation. subs is a pointer to four groups of three
2178  * strings:
2179  *      0-2     --> Operate on ints
2180  *      3-5     --> Operate on unsigneds
2181  *      6-8     --> Operate on longs
2182  *      9-11    --> Operate on unsigned longs
2183  *
2184  * The first subroutine names in each string group is used to encode an
2185  * operation with a zero constant, the second to encode an operation with
2186  * a 8 bit constant, and the third is used in all other cases.
2187  */
2188 {
2189     unsigned offs;
2190
2191     /* Determine the offset into the array */
2192     offs = (flags & CF_UNSIGNED)? 3 : 0;
2193     switch (flags & CF_TYPE) {
2194         case CF_CHAR:
2195         case CF_INT:
2196             break;
2197
2198         case CF_LONG:
2199             offs += 6;
2200             break;
2201
2202         default:
2203             typeerror (flags);
2204     }
2205
2206     /* Encode the operation */
2207     if (flags & CF_CONST) {
2208         /* Constant value given */
2209         if (val == 0 && subs [offs+0]) {
2210             /* Special case: constant with value zero */
2211             AddCodeLine ("jsr %s", subs [offs+0]);
2212         } else if (val < 0x100 && subs [offs+1]) {
2213             /* Special case: constant with high byte zero */
2214             ldaconst (val);             /* Load low byte */
2215             AddCodeLine ("jsr %s", subs [offs+1]);
2216         } else {
2217             /* Others: arbitrary constant value */
2218             g_getimmed (flags, val, 0);                 /* Load value */
2219             AddCodeLine ("jsr %s", subs [offs+2]);
2220         }
2221     } else {
2222         /* Value not constant (is already in (e)ax) */
2223         AddCodeLine ("jsr %s", subs [offs+2]);
2224     }
2225
2226     /* The operation will pop it's argument */
2227     pop (flags);
2228 }
2229
2230
2231
2232 void g_test (unsigned flags)
2233 /* Test the value in the primary and set the condition codes */
2234 {
2235     switch (flags & CF_TYPE) {
2236
2237         case CF_CHAR:
2238             if (flags & CF_FORCECHAR) {
2239                 AddCodeLine ("tax");
2240                 break;
2241             }
2242             /* FALLTHROUGH */
2243
2244         case CF_INT:
2245             AddCodeLine ("stx tmp1");
2246             AddCodeLine ("ora tmp1");
2247             break;
2248
2249         case CF_LONG:
2250             if (flags & CF_UNSIGNED) {
2251                 AddCodeLine ("jsr utsteax");
2252             } else {
2253                 AddCodeLine ("jsr tsteax");
2254             }
2255             break;
2256
2257         default:
2258             typeerror (flags);
2259
2260     }
2261 }
2262
2263
2264
2265 void g_push (unsigned flags, unsigned long val)
2266 /* Push the primary register or a constant value onto the stack */
2267 {
2268     unsigned char hi;
2269
2270     if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
2271
2272         /* We have a constant 8 or 16 bit value */
2273         if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
2274
2275             /* Handle as 8 bit value */
2276             if (CodeSizeFactor >= 165 || val > 2) {
2277                 ldaconst (val);
2278                 AddCodeLine ("jsr pusha");
2279             } else {
2280                 AddCodeLine ("jsr pushc%d", (int) val);
2281             }
2282
2283         } else {
2284
2285             /* Handle as 16 bit value */
2286             hi = (unsigned char) (val >> 8);
2287             if (val <= 7) {
2288                 AddCodeLine ("jsr push%u", (unsigned) val);
2289             } else if (hi == 0 || hi == 0xFF) {
2290                 /* Use special function */
2291                 ldaconst (val);
2292                 AddCodeLine ("jsr %s", (hi == 0)? "pusha0" : "pushaFF");
2293             } else {
2294                 /* Long way ... */
2295                 g_getimmed (flags, val, 0);
2296                 AddCodeLine ("jsr pushax");
2297             }
2298         }
2299
2300     } else {
2301
2302         /* Value is not 16 bit or not constant */
2303         if (flags & CF_CONST) {
2304             /* Constant 32 bit value, load into eax */
2305             g_getimmed (flags, val, 0);
2306         }
2307
2308         /* Push the primary register */
2309         switch (flags & CF_TYPE) {
2310
2311             case CF_CHAR:
2312                 if (flags & CF_FORCECHAR) {
2313                     /* Handle as char */
2314                     AddCodeLine ("jsr pusha");
2315                     break;
2316                 }
2317                 /* FALL THROUGH */
2318             case CF_INT:
2319                 AddCodeLine ("jsr pushax");
2320                 break;
2321
2322             case CF_LONG:
2323                 AddCodeLine ("jsr pusheax");
2324                 break;
2325
2326             default:
2327                 typeerror (flags);
2328
2329         }
2330
2331     }
2332
2333     /* Adjust the stack offset */
2334     push (flags);
2335 }
2336
2337
2338
2339 void g_swap (unsigned flags)
2340 /* Swap the primary register and the top of the stack. flags give the type
2341  * of *both* values (must have same size).
2342  */
2343 {
2344     switch (flags & CF_TYPE) {
2345
2346         case CF_CHAR:
2347         case CF_INT:
2348             AddCodeLine ("jsr swapstk");
2349             break;
2350
2351         case CF_LONG:
2352             AddCodeLine ("jsr swapestk");
2353             break;
2354
2355         default:
2356             typeerror (flags);
2357
2358     }
2359 }
2360
2361
2362
2363 void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
2364 /* Call the specified subroutine name */
2365 {
2366     if ((Flags & CF_FIXARGC) == 0) {
2367         /* Pass the argument count */
2368         ldyconst (ArgSize);
2369     }
2370     AddCodeLine ("jsr _%s", Label);
2371     oursp += ArgSize;           /* callee pops args */
2372 }
2373
2374
2375
2376 void g_callind (unsigned Flags, unsigned ArgSize, int Offs)
2377 /* Call subroutine indirect */
2378 {
2379     if ((Flags & CF_LOCAL) == 0) {
2380         /* Address is in a/x */
2381         if ((Flags & CF_FIXARGC) == 0) {
2382             /* Pass arg count */
2383             ldyconst (ArgSize);
2384         }
2385         AddCodeLine ("jsr callax");
2386     } else {
2387         /* The address is on stack, offset is on Val */
2388         Offs -= oursp;
2389         CheckLocalOffs (Offs);
2390         AddCodeLine ("pha");
2391         AddCodeLine ("ldy #$%02X", Offs);
2392         AddCodeLine ("lda (sp),y");
2393         AddCodeLine ("sta jmpvec+1");
2394         AddCodeLine ("iny");
2395         AddCodeLine ("lda (sp),y");
2396         AddCodeLine ("sta jmpvec+2");
2397         AddCodeLine ("pla");
2398         AddCodeLine ("jsr jmpvec");
2399     }
2400
2401     /* Callee pops args */
2402     oursp += ArgSize;
2403 }
2404
2405
2406
2407 void g_jump (unsigned Label)
2408 /* Jump to specified internal label number */
2409 {
2410     AddCodeLine ("jmp %s", LocalLabelName (Label));
2411 }
2412
2413
2414
2415 void g_switch (unsigned Flags)
2416 /* Output switch statement preamble */
2417 {
2418     switch (Flags & CF_TYPE) {
2419
2420         case CF_CHAR:
2421         case CF_INT:
2422             AddCodeLine ("jsr switch");
2423             break;
2424
2425         case CF_LONG:
2426             AddCodeLine ("jsr lswitch");
2427             break;
2428
2429         default:
2430             typeerror (Flags);
2431
2432     }
2433 }
2434
2435
2436
2437 void g_case (unsigned flags, unsigned label, unsigned long val)
2438 /* Create table code for one case selector */
2439 {
2440     switch (flags & CF_TYPE) {
2441
2442         case CF_CHAR:
2443         case CF_INT:
2444             AddCodeLine (".word $%04X, %s",
2445                          (unsigned)(val & 0xFFFF),
2446                          LocalLabelName (label));
2447             break;
2448
2449         case CF_LONG:
2450             AddCodeLine (".dword $%08lX", val);
2451             AddCodeLine (".word %s", LocalLabelName (label));
2452             break;
2453
2454         default:
2455             typeerror (flags);
2456
2457     }
2458 }
2459
2460
2461
2462 void g_truejump (unsigned flags, unsigned label)
2463 /* Jump to label if zero flag clear */
2464 {
2465     AddCodeLine ("jne %s", LocalLabelName (label));
2466 }
2467
2468
2469
2470 void g_falsejump (unsigned flags, unsigned label)
2471 /* Jump to label if zero flag set */
2472 {
2473     AddCodeLine ("jeq %s", LocalLabelName (label));
2474 }
2475
2476
2477
2478 static void mod_internal (int k, char* verb1, char* verb2)
2479 {
2480     if (k <= 8) {
2481         AddCodeLine ("jsr %ssp%c", verb1, k + '0');
2482     } else {
2483         CheckLocalOffs (k);
2484         ldyconst (k);
2485         AddCodeLine ("jsr %ssp", verb2);
2486     }
2487 }
2488
2489
2490
2491 void g_space (int space)
2492 /* Create or drop space on the stack */
2493 {
2494     if (space < 0) {
2495         mod_internal (-space, "inc", "addy");
2496     } else if (space > 0) {
2497         mod_internal (space, "dec", "suby");
2498     }
2499 }
2500
2501
2502
2503 void g_cstackcheck (void)
2504 /* Check for a C stack overflow */
2505 {
2506     AddCodeLine ("jsr cstkchk");
2507 }
2508
2509
2510
2511 void g_stackcheck (void)
2512 /* Check for a stack overflow */
2513 {
2514     AddCodeLine ("jsr stkchk");
2515 }
2516
2517
2518
2519 void g_add (unsigned flags, unsigned long val)
2520 /* Primary = TOS + Primary */
2521 {
2522     static char* ops [12] = {
2523         0,              "tosadda0",     "tosaddax",
2524         0,              "tosadda0",     "tosaddax",
2525         0,              0,              "tosaddeax",
2526         0,              0,              "tosaddeax",
2527     };
2528
2529     if (flags & CF_CONST) {
2530         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2531         g_push (flags & ~CF_CONST, 0);
2532     }
2533     oper (flags, val, ops);
2534 }
2535
2536
2537
2538 void g_sub (unsigned flags, unsigned long val)
2539 /* Primary = TOS - Primary */
2540 {
2541     static char* ops [12] = {
2542         0,              "tossuba0",     "tossubax",
2543         0,              "tossuba0",     "tossubax",
2544         0,              0,              "tossubeax",
2545         0,              0,              "tossubeax",
2546     };
2547
2548     if (flags & CF_CONST) {
2549         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2550         g_push (flags & ~CF_CONST, 0);
2551     }
2552     oper (flags, val, ops);
2553 }
2554
2555
2556
2557 void g_rsub (unsigned flags, unsigned long val)
2558 /* Primary = Primary - TOS */
2559 {
2560     static char* ops [12] = {
2561         0,              "tosrsuba0",    "tosrsubax",
2562         0,              "tosrsuba0",    "tosrsubax",
2563         0,              0,              "tosrsubeax",
2564         0,              0,              "tosrsubeax",
2565     };
2566     oper (flags, val, ops);
2567 }
2568
2569
2570
2571 void g_mul (unsigned flags, unsigned long val)
2572 /* Primary = TOS * Primary */
2573 {
2574     static char* ops [12] = {
2575         0,              "tosmula0",     "tosmulax",
2576         0,              "tosumula0",    "tosumulax",
2577         0,              0,              "tosmuleax",
2578         0,              0,              "tosumuleax",
2579     };
2580
2581     int p2;
2582
2583     /* Do strength reduction if the value is constant and a power of two */
2584     if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2585         /* Generate a shift instead */
2586         g_asl (flags, p2);
2587         return;
2588     }
2589
2590     /* If the right hand side is const, the lhs is not on stack but still
2591      * in the primary register.
2592      */
2593     if (flags & CF_CONST) {
2594
2595         switch (flags & CF_TYPE) {
2596
2597             case CF_CHAR:
2598                 if (flags & CF_FORCECHAR) {
2599                     /* Handle some special cases */
2600                     switch (val) {
2601
2602                         case 3:
2603                             AddCodeLine ("sta tmp1");
2604                             AddCodeLine ("asl a");
2605                             AddCodeLine ("clc");
2606                             AddCodeLine ("adc tmp1");
2607                             return;
2608
2609                         case 5:
2610                             AddCodeLine ("sta tmp1");
2611                             AddCodeLine ("asl a");
2612                             AddCodeLine ("asl a");
2613                             AddCodeLine ("clc");
2614                             AddCodeLine ("adc tmp1");
2615                             return;
2616
2617                         case 10:
2618                             AddCodeLine ("sta tmp1");
2619                             AddCodeLine ("asl a");
2620                             AddCodeLine ("asl a");
2621                             AddCodeLine ("clc");
2622                             AddCodeLine ("adc tmp1");
2623                             AddCodeLine ("asl a");
2624                             return;
2625                     }
2626                 }
2627                 /* FALLTHROUGH */
2628
2629             case CF_INT:
2630                 break;
2631
2632             case CF_LONG:
2633                 break;
2634
2635             default:
2636                 typeerror (flags);
2637         }
2638
2639         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2640          * into the normal, non-optimized stuff.
2641          */
2642         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2643         g_push (flags & ~CF_CONST, 0);
2644
2645     }
2646
2647     /* Use long way over the stack */
2648     oper (flags, val, ops);
2649 }
2650
2651
2652
2653 void g_div (unsigned flags, unsigned long val)
2654 /* Primary = TOS / Primary */
2655 {
2656     static char* ops [12] = {
2657         0,              "tosdiva0",     "tosdivax",
2658         0,              "tosudiva0",    "tosudivax",
2659         0,              0,              "tosdiveax",
2660         0,              0,              "tosudiveax",
2661     };
2662
2663     /* Do strength reduction if the value is constant and a power of two */
2664     int p2;
2665     if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2666         /* Generate a shift instead */
2667         g_asr (flags, p2);
2668     } else {
2669         /* Generate a division */
2670         if (flags & CF_CONST) {
2671             /* lhs is not on stack */
2672             flags &= ~CF_FORCECHAR;     /* Handle chars as ints */
2673             g_push (flags & ~CF_CONST, 0);
2674         }
2675         oper (flags, val, ops);
2676     }
2677 }
2678
2679
2680
2681 void g_mod (unsigned flags, unsigned long val)
2682 /* Primary = TOS % Primary */
2683 {
2684     static char* ops [12] = {
2685         0,              "tosmoda0",     "tosmodax",
2686         0,              "tosumoda0",    "tosumodax",
2687         0,              0,              "tosmodeax",
2688         0,              0,              "tosumodeax",
2689     };
2690     int p2;
2691
2692     /* Check if we can do some cost reduction */
2693     if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2694         /* We can do that with an AND operation */
2695         g_and (flags, val - 1);
2696     } else {
2697         /* Do it the hard way... */
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);
2702         }
2703         oper (flags, val, ops);
2704     }
2705 }
2706
2707
2708
2709 void g_or (unsigned flags, unsigned long val)
2710 /* Primary = TOS | Primary */
2711 {
2712     static char* ops [12] = {
2713         0,              "tosora0",      "tosorax",
2714         0,              "tosora0",      "tosorax",
2715         0,              0,              "tosoreax",
2716         0,              0,              "tosoreax",
2717     };
2718
2719     /* If the right hand side is const, the lhs is not on stack but still
2720      * in the primary register.
2721      */
2722     if (flags & CF_CONST) {
2723
2724         switch (flags & CF_TYPE) {
2725
2726             case CF_CHAR:
2727                 if (flags & CF_FORCECHAR) {
2728                     if ((val & 0xFF) != 0xFF) {
2729                         AddCodeLine ("ora #$%02X", (unsigned char)val);
2730                     }
2731                     return;
2732                 }
2733                 /* FALLTHROUGH */
2734
2735             case CF_INT:
2736                 if (val <= 0xFF) {
2737                     AddCodeLine ("ora #$%02X", (unsigned char)val);
2738                     return;
2739                 }
2740                 break;
2741
2742             case CF_LONG:
2743                 if (val <= 0xFF) {
2744                     AddCodeLine ("ora #$%02X", (unsigned char)val);
2745                     return;
2746                 }
2747                 break;
2748
2749             default:
2750                 typeerror (flags);
2751         }
2752
2753         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2754          * into the normal, non-optimized stuff.
2755          */
2756         g_push (flags & ~CF_CONST, 0);
2757
2758     }
2759
2760     /* Use long way over the stack */
2761     oper (flags, val, ops);
2762 }
2763
2764
2765
2766 void g_xor (unsigned flags, unsigned long val)
2767 /* Primary = TOS ^ Primary */
2768 {
2769     static char* ops [12] = {
2770         0,              "tosxora0",     "tosxorax",
2771         0,              "tosxora0",     "tosxorax",
2772         0,              0,              "tosxoreax",
2773         0,              0,              "tosxoreax",
2774     };
2775
2776
2777     /* If the right hand side is const, the lhs is not on stack but still
2778      * in the primary register.
2779      */
2780     if (flags & CF_CONST) {
2781
2782         switch (flags & CF_TYPE) {
2783
2784             case CF_CHAR:
2785                 if (flags & CF_FORCECHAR) {
2786                     if ((val & 0xFF) != 0) {
2787                         AddCodeLine ("eor #$%02X", (unsigned char)val);
2788                     }
2789                     return;
2790                 }
2791                 /* FALLTHROUGH */
2792
2793             case CF_INT:
2794                 if (val <= 0xFF) {
2795                     if (val != 0) {
2796                         AddCodeLine ("eor #$%02X", (unsigned char)val);
2797                     }
2798                     return;
2799                 } else if ((val & 0xFF) == 0) {
2800                     AddCodeLine ("pha");
2801                     AddCodeLine ("txa");
2802                     AddCodeLine ("eor #$%02X", (unsigned char)(val >> 8));
2803                     AddCodeLine ("tax");
2804                     AddCodeLine ("pla");
2805                     return;
2806                 }
2807                 break;
2808
2809             case CF_LONG:
2810                 if (val <= 0xFF) {
2811                     if (val != 0) {
2812                         AddCodeLine ("eor #$%02X", (unsigned char)val);
2813                     }
2814                     return;
2815                 }
2816                 break;
2817
2818             default:
2819                 typeerror (flags);
2820         }
2821
2822         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2823          * into the normal, non-optimized stuff.
2824          */
2825         g_push (flags & ~CF_CONST, 0);
2826
2827     }
2828
2829     /* Use long way over the stack */
2830     oper (flags, val, ops);
2831 }
2832
2833
2834
2835 void g_and (unsigned flags, unsigned long val)
2836 /* Primary = TOS & Primary */
2837 {
2838     static char* ops [12] = {
2839         0,              "tosanda0",     "tosandax",
2840         0,              "tosanda0",     "tosandax",
2841         0,              0,              "tosandeax",
2842         0,              0,              "tosandeax",
2843     };
2844
2845     /* If the right hand side is const, the lhs is not on stack but still
2846      * in the primary register.
2847      */
2848     if (flags & CF_CONST) {
2849
2850         switch (flags & CF_TYPE) {
2851
2852             case CF_CHAR:
2853                 if (flags & CF_FORCECHAR) {
2854                     AddCodeLine ("and #$%02X", (unsigned char)val);
2855                     return;
2856                 }
2857                 /* FALLTHROUGH */
2858             case CF_INT:
2859                 if ((val & 0xFFFF) != 0xFFFF) {
2860                     if (val <= 0xFF) {
2861                         ldxconst (0);
2862                         if (val == 0) {
2863                             ldaconst (0);
2864                         } else if (val != 0xFF) {
2865                             AddCodeLine ("and #$%02X", (unsigned char)val);
2866                         }
2867                     } else if ((val & 0xFF00) == 0xFF00) {
2868                         AddCodeLine ("and #$%02X", (unsigned char)val);
2869                     } else if ((val & 0x00FF) == 0x0000) {
2870                         AddCodeLine ("txa");
2871                         AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2872                         AddCodeLine ("tax");
2873                         ldaconst (0);
2874                     } else {
2875                         AddCodeLine ("tay");
2876                         AddCodeLine ("txa");
2877                         AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2878                         AddCodeLine ("tax");
2879                         AddCodeLine ("tya");
2880                         if ((val & 0x00FF) != 0x00FF) {
2881                             AddCodeLine ("and #$%02X", (unsigned char)val);
2882                         }
2883                     }
2884                 }
2885                 return;
2886
2887             case CF_LONG:
2888                 if (val <= 0xFF) {
2889                     ldxconst (0);
2890                     AddCodeLine ("stx sreg+1");
2891                     AddCodeLine ("stx sreg");
2892                     if ((val & 0xFF) != 0xFF) {
2893                          AddCodeLine ("and #$%02X", (unsigned char)val);
2894                     }
2895                     return;
2896                 } else if (val == 0xFF00) {
2897                     ldaconst (0);
2898                     AddCodeLine ("sta sreg+1");
2899                     AddCodeLine ("sta sreg");
2900                     return;
2901                 }
2902                 break;
2903
2904             default:
2905                 typeerror (flags);
2906         }
2907
2908         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2909          * into the normal, non-optimized stuff.
2910          */
2911         g_push (flags & ~CF_CONST, 0);
2912
2913     }
2914
2915     /* Use long way over the stack */
2916     oper (flags, val, ops);
2917 }
2918
2919
2920
2921 void g_asr (unsigned flags, unsigned long val)
2922 /* Primary = TOS >> Primary */
2923 {
2924     static char* ops [12] = {
2925         0,              "tosasra0",     "tosasrax",
2926         0,              "tosshra0",     "tosshrax",
2927         0,              0,              "tosasreax",
2928         0,              0,              "tosshreax",
2929     };
2930
2931     /* If the right hand side is const, the lhs is not on stack but still
2932      * in the primary register.
2933      */
2934     if (flags & CF_CONST) {
2935
2936         switch (flags & CF_TYPE) {
2937
2938             case CF_CHAR:
2939             case CF_INT:
2940                 if (val >= 1 && val <= 4) {
2941                     if (flags & CF_UNSIGNED) {
2942                         AddCodeLine ("jsr shrax%ld", val);
2943                     } else {
2944                         AddCodeLine ("jsr asrax%ld", val);
2945                     }
2946                     return;
2947                 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2948                     AddCodeLine ("txa");
2949                     ldxconst (0);
2950                     return;
2951                 }
2952                 break;
2953
2954             case CF_LONG:
2955                 if (val >= 1 && val <= 4) {
2956                     if (flags & CF_UNSIGNED) {
2957                         AddCodeLine ("jsr shreax%ld", val);
2958                     } else {
2959                         AddCodeLine ("jsr asreax%ld", val);
2960                     }
2961                     return;
2962                 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2963                     AddCodeLine ("txa");
2964                     AddCodeLine ("ldx sreg");
2965                     AddCodeLine ("ldy sreg+1");
2966                     AddCodeLine ("sty sreg");
2967                     AddCodeLine ("ldy #$00");
2968                     AddCodeLine ("sty sreg+1");
2969                     return;
2970                 } else if (val == 16) {
2971                     AddCodeLine ("ldy #$00");
2972                     AddCodeLine ("ldx sreg+1");
2973                     if ((flags & CF_UNSIGNED) == 0) {
2974                         unsigned L = GetLocalLabel();
2975                         AddCodeLine ("bpl %s", LocalLabelName (L));
2976                         AddCodeLine ("dey");
2977                         g_defcodelabel (L);
2978                     }
2979                     AddCodeLine ("lda sreg");
2980                     AddCodeLine ("sty sreg+1");
2981                     AddCodeLine ("sty sreg");
2982                     return;
2983                 }
2984                 break;
2985
2986             default:
2987                 typeerror (flags);
2988         }
2989
2990         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2991          * into the normal, non-optimized stuff.
2992          */
2993         g_push (flags & ~CF_CONST, 0);
2994
2995     }
2996
2997     /* Use long way over the stack */
2998     oper (flags, val, ops);
2999 }
3000
3001
3002
3003 void g_asl (unsigned flags, unsigned long val)
3004 /* Primary = TOS << Primary */
3005 {
3006     static char* ops [12] = {
3007         0,              "tosasla0",     "tosaslax",
3008         0,              "tosshla0",     "tosshlax",
3009         0,              0,              "tosasleax",
3010         0,              0,              "tosshleax",
3011     };
3012
3013
3014     /* If the right hand side is const, the lhs is not on stack but still
3015      * in the primary register.
3016      */
3017     if (flags & CF_CONST) {
3018
3019         switch (flags & CF_TYPE) {
3020
3021             case CF_CHAR:
3022             case CF_INT:
3023                 if (val >= 1 && val <= 4) {
3024                     if (flags & CF_UNSIGNED) {
3025                         AddCodeLine ("jsr shlax%ld", val);
3026                     } else {
3027                         AddCodeLine ("jsr aslax%ld", val);
3028                     }
3029                     return;
3030                 } else if (val == 8) {
3031                     AddCodeLine ("tax");
3032                     AddCodeLine ("lda #$00");
3033                     return;
3034                 }
3035                 break;
3036
3037             case CF_LONG:
3038                 if (val >= 1 && val <= 4) {
3039                     if (flags & CF_UNSIGNED) {
3040                         AddCodeLine ("jsr shleax%ld", val);
3041                     } else {
3042                         AddCodeLine ("jsr asleax%ld", val);
3043                     }
3044                     return;
3045                 } else if (val == 8) {
3046                     AddCodeLine ("ldy sreg");
3047                     AddCodeLine ("sty sreg+1");
3048                     AddCodeLine ("stx sreg");
3049                     AddCodeLine ("tax");
3050                     AddCodeLine ("lda #$00");
3051                     return;
3052                 } else if (val == 16) {
3053                     AddCodeLine ("stx sreg+1");
3054                     AddCodeLine ("sta sreg");
3055                     AddCodeLine ("lda #$00");
3056                     AddCodeLine ("tax");
3057                     return;
3058                 }
3059                 break;
3060
3061             default:
3062                 typeerror (flags);
3063         }
3064
3065         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3066          * into the normal, non-optimized stuff.
3067          */
3068         g_push (flags & ~CF_CONST, 0);
3069
3070     }
3071
3072     /* Use long way over the stack */
3073     oper (flags, val, ops);
3074 }
3075
3076
3077
3078 void g_neg (unsigned flags)
3079 /* Primary = -Primary */
3080 {
3081     switch (flags & CF_TYPE) {
3082
3083         case CF_CHAR:
3084         case CF_INT:
3085             AddCodeLine ("jsr negax");
3086             break;
3087
3088         case CF_LONG:
3089             AddCodeLine ("jsr negeax");
3090             break;
3091
3092         default:
3093             typeerror (flags);
3094     }
3095 }
3096
3097
3098
3099 void g_bneg (unsigned flags)
3100 /* Primary = !Primary */
3101 {
3102     switch (flags & CF_TYPE) {
3103
3104         case CF_CHAR:
3105             AddCodeLine ("jsr bnega");
3106             break;
3107
3108         case CF_INT:
3109             AddCodeLine ("jsr bnegax");
3110             break;
3111
3112         case CF_LONG:
3113             AddCodeLine ("jsr bnegeax");
3114             break;
3115
3116         default:
3117             typeerror (flags);
3118     }
3119 }
3120
3121
3122
3123 void g_com (unsigned flags)
3124 /* Primary = ~Primary */
3125 {
3126     switch (flags & CF_TYPE) {
3127
3128         case CF_CHAR:
3129         case CF_INT:
3130             AddCodeLine ("jsr complax");
3131             break;
3132
3133         case CF_LONG:
3134             AddCodeLine ("jsr compleax");
3135             break;
3136
3137         default:
3138             typeerror (flags);
3139     }
3140 }
3141
3142
3143
3144 void g_inc (unsigned flags, unsigned long val)
3145 /* Increment the primary register by a given number */
3146 {
3147     /* Don't inc by zero */
3148     if (val == 0) {
3149         return;
3150     }
3151
3152     /* Generate code for the supported types */
3153     flags &= ~CF_CONST;
3154     switch (flags & CF_TYPE) {
3155
3156         case CF_CHAR:
3157             if (flags & CF_FORCECHAR) {
3158                 if (CPU == CPU_65C02 && val <= 2) {
3159                     while (val--) {
3160                         AddCodeLine ("ina");
3161                     }
3162                 } else {
3163                     AddCodeLine ("clc");
3164                     AddCodeLine ("adc #$%02X", (unsigned char)val);
3165                 }
3166                 break;
3167             }
3168             /* FALLTHROUGH */
3169
3170         case CF_INT:
3171             if (CPU == CPU_65C02 && val == 1) {
3172                 unsigned L = GetLocalLabel();
3173                 AddCodeLine ("ina");
3174                 AddCodeLine ("bne %s", LocalLabelName (L));
3175                 AddCodeLine ("inx");
3176                 g_defcodelabel (L);
3177             } else if (CodeSizeFactor < 200) {
3178                 /* Use jsr calls */
3179                 if (val <= 8) {
3180                     AddCodeLine ("jsr incax%lu", val);
3181                 } else if (val <= 255) {
3182                     ldyconst (val);
3183                     AddCodeLine ("jsr incaxy");
3184                 } else {
3185                     g_add (flags | CF_CONST, val);
3186                 }
3187             } else {
3188                 /* Inline the code */
3189                 if (val < 0x300) {
3190                     if ((val & 0xFF) != 0) {
3191                         unsigned L = GetLocalLabel();
3192                         AddCodeLine ("clc");
3193                         AddCodeLine ("adc #$%02X", (unsigned char) val);
3194                         AddCodeLine ("bcc %s", LocalLabelName (L));
3195                         AddCodeLine ("inx");
3196                         g_defcodelabel (L);
3197                     }
3198                     if (val >= 0x100) {
3199                         AddCodeLine ("inx");
3200                     }
3201                     if (val >= 0x200) {
3202                         AddCodeLine ("inx");
3203                     }
3204                 } else {
3205                     AddCodeLine ("clc");
3206                     if ((val & 0xFF) != 0) {
3207                         AddCodeLine ("adc #$%02X", (unsigned char) val);
3208                     }
3209                     AddCodeLine ("pha");
3210                     AddCodeLine ("txa");
3211                     AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3212                     AddCodeLine ("tax");
3213                     AddCodeLine ("pla");
3214                 }
3215             }
3216             break;
3217
3218         case CF_LONG:
3219             if (val <= 255) {
3220                 ldyconst (val);
3221                 AddCodeLine ("jsr inceaxy");
3222             } else {
3223                 g_add (flags | CF_CONST, val);
3224             }
3225             break;
3226
3227         default:
3228             typeerror (flags);
3229
3230     }
3231 }
3232
3233
3234
3235 void g_dec (unsigned flags, unsigned long val)
3236 /* Decrement the primary register by a given number */
3237 {
3238     /* Don't dec by zero */
3239     if (val == 0) {
3240         return;
3241     }
3242
3243     /* Generate code for the supported types */
3244     flags &= ~CF_CONST;
3245     switch (flags & CF_TYPE) {
3246
3247         case CF_CHAR:
3248             if (flags & CF_FORCECHAR) {
3249                 if (CPU == CPU_65C02 && val <= 2) {
3250                     while (val--) {
3251                         AddCodeLine ("dea");
3252                     }
3253                 } else {
3254                     AddCodeLine ("sec");
3255                     AddCodeLine ("sbc #$%02X", (unsigned char)val);
3256                 }
3257                 break;
3258             }
3259             /* FALLTHROUGH */
3260
3261         case CF_INT:
3262             if (CodeSizeFactor < 200) {
3263                 /* Use subroutines */
3264                 if (val <= 8) {
3265                     AddCodeLine ("jsr decax%d", (int) val);
3266                 } else if (val <= 255) {
3267                     ldyconst (val);
3268                     AddCodeLine ("jsr decaxy");
3269                 } else {
3270                     g_sub (flags | CF_CONST, val);
3271                 }
3272             } else {
3273                 /* Inline the code */
3274                 if (val < 0x300) {
3275                     if ((val & 0xFF) != 0) {
3276                         unsigned L = GetLocalLabel();
3277                         AddCodeLine ("sec");
3278                         AddCodeLine ("sbc #$%02X", (unsigned char) val);
3279                         AddCodeLine ("bcs %s", LocalLabelName (L));
3280                         AddCodeLine ("dex");
3281                         g_defcodelabel (L);
3282                     }
3283                     if (val >= 0x100) {
3284                         AddCodeLine ("dex");
3285                     }
3286                     if (val >= 0x200) {
3287                         AddCodeLine ("dex");
3288                     }
3289                 } else {
3290                     AddCodeLine ("sec");
3291                     if ((val & 0xFF) != 0) {
3292                         AddCodeLine ("sbc #$%02X", (unsigned char) val);
3293                     }
3294                     AddCodeLine ("pha");
3295                     AddCodeLine ("txa");
3296                     AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3297                     AddCodeLine ("tax");
3298                     AddCodeLine ("pla");
3299                 }
3300             }
3301             break;
3302
3303         case CF_LONG:
3304             if (val <= 255) {
3305                 ldyconst (val);
3306                 AddCodeLine ("jsr deceaxy");
3307             } else {
3308                 g_sub (flags | CF_CONST, val);
3309             }
3310             break;
3311
3312         default:
3313             typeerror (flags);
3314
3315     }
3316 }
3317
3318
3319
3320 /*
3321  * Following are the conditional operators. They compare the TOS against
3322  * the primary and put a literal 1 in the primary if the condition is
3323  * true, otherwise they clear the primary register
3324  */
3325
3326
3327
3328 void g_eq (unsigned flags, unsigned long val)
3329 /* Test for equal */
3330 {
3331     static char* ops [12] = {
3332         "toseq00",      "toseqa0",      "toseqax",
3333         "toseq00",      "toseqa0",      "toseqax",
3334         0,              0,              "toseqeax",
3335         0,              0,              "toseqeax",
3336     };
3337
3338     unsigned L;
3339
3340     /* If the right hand side is const, the lhs is not on stack but still
3341      * in the primary register.
3342      */
3343     if (flags & CF_CONST) {
3344
3345         switch (flags & CF_TYPE) {
3346
3347             case CF_CHAR:
3348                 if (flags & CF_FORCECHAR) {
3349                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3350                     AddCodeLine ("jsr booleq");
3351                     return;
3352                 }
3353                 /* FALLTHROUGH */
3354
3355             case CF_INT:
3356                 L = GetLocalLabel();
3357                 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3358                 AddCodeLine ("bne %s", LocalLabelName (L));
3359                 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3360                 g_defcodelabel (L);
3361                 AddCodeLine ("jsr booleq");
3362                 return;
3363
3364             case CF_LONG:
3365                 break;
3366
3367             default:
3368                 typeerror (flags);
3369         }
3370
3371         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3372          * into the normal, non-optimized stuff.
3373          */
3374         g_push (flags & ~CF_CONST, 0);
3375
3376     }
3377
3378     /* Use long way over the stack */
3379     oper (flags, val, ops);
3380 }
3381
3382
3383
3384 void g_ne (unsigned flags, unsigned long val)
3385 /* Test for not equal */
3386 {
3387     static char* ops [12] = {
3388         "tosne00",      "tosnea0",      "tosneax",
3389         "tosne00",      "tosnea0",      "tosneax",
3390         0,              0,              "tosneeax",
3391         0,              0,              "tosneeax",
3392     };
3393
3394     unsigned L;
3395
3396     /* If the right hand side is const, the lhs is not on stack but still
3397      * in the primary register.
3398      */
3399     if (flags & CF_CONST) {
3400
3401         switch (flags & CF_TYPE) {
3402
3403             case CF_CHAR:
3404                 if (flags & CF_FORCECHAR) {
3405                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3406                     AddCodeLine ("jsr boolne");
3407                     return;
3408                 }
3409                 /* FALLTHROUGH */
3410
3411             case CF_INT:
3412                 L = GetLocalLabel();
3413                 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3414                 AddCodeLine ("bne %s", LocalLabelName (L));
3415                 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3416                 g_defcodelabel (L);
3417                 AddCodeLine ("jsr boolne");
3418                 return;
3419
3420             case CF_LONG:
3421                 break;
3422
3423             default:
3424                 typeerror (flags);
3425         }
3426
3427         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3428          * into the normal, non-optimized stuff.
3429          */
3430         g_push (flags & ~CF_CONST, 0);
3431
3432     }
3433
3434     /* Use long way over the stack */
3435     oper (flags, val, ops);
3436 }
3437
3438
3439
3440 void g_lt (unsigned flags, unsigned long val)
3441 /* Test for less than */
3442 {
3443     static char* ops [12] = {
3444         "toslt00",      "toslta0",      "tosltax",
3445         "tosult00",     "tosulta0",     "tosultax",
3446         0,              0,              "toslteax",
3447         0,              0,              "tosulteax",
3448     };
3449
3450     /* If the right hand side is const, the lhs is not on stack but still
3451      * in the primary register.
3452      */
3453     if (flags & CF_CONST) {
3454
3455         /* Give a warning in some special cases */
3456         if ((flags & CF_UNSIGNED) && val == 0) {
3457             Warning ("Condition is never true");
3458         }
3459
3460         /* Look at the type */
3461         switch (flags & CF_TYPE) {
3462
3463             case CF_CHAR:
3464                 if (flags & CF_FORCECHAR) {
3465                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3466                     if (flags & CF_UNSIGNED) {
3467                         AddCodeLine ("jsr boolult");
3468                     } else {
3469                         AddCodeLine ("jsr boollt");
3470                     }
3471                     return;
3472                 }
3473                 /* FALLTHROUGH */
3474
3475             case CF_INT:
3476                 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3477                     /* If we have a signed compare against zero, we only need to
3478                      * test the high byte.
3479                      */
3480                     AddCodeLine ("txa");
3481                     AddCodeLine ("jsr boollt");
3482                     return;
3483                 }
3484                 /* Direct code only for unsigned data types */
3485                 if (flags & CF_UNSIGNED) {
3486                     unsigned L = GetLocalLabel();
3487                     AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3488                     AddCodeLine ("bne %s", LocalLabelName (L));
3489                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3490                     g_defcodelabel (L);
3491                     AddCodeLine ("jsr boolult");
3492                     return;
3493                 }
3494                 break;
3495
3496             case CF_LONG:
3497                 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3498                     /* If we have a signed compare against zero, we only need to
3499                      * test the high byte.
3500                      */
3501                     AddCodeLine ("lda sreg+1");
3502                     AddCodeLine ("jsr boollt");
3503                     return;
3504                 }
3505                 break;
3506
3507             default:
3508                 typeerror (flags);
3509         }
3510
3511         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3512          * into the normal, non-optimized stuff.
3513          */
3514         g_push (flags & ~CF_CONST, 0);
3515
3516     }
3517
3518     /* Use long way over the stack */
3519     oper (flags, val, ops);
3520 }
3521
3522
3523
3524 void g_le (unsigned flags, unsigned long val)
3525 /* Test for less than or equal to */
3526 {
3527     static char* ops [12] = {
3528         "tosle00",      "toslea0",      "tosleax",
3529         "tosule00",     "tosulea0",     "tosuleax",
3530         0,              0,              "tosleeax",
3531         0,              0,              "tosuleeax",
3532     };
3533
3534
3535     /* If the right hand side is const, the lhs is not on stack but still
3536      * in the primary register.
3537      */
3538     if (flags & CF_CONST) {
3539
3540         /* <= is not very effective on the 6502, so try to convert
3541          * it into < if the value is in a valid range.
3542          */
3543
3544         /* Look at the type */
3545         switch (flags & CF_TYPE) {
3546
3547             case CF_CHAR:
3548                 if (flags & CF_FORCECHAR) {
3549                     if (flags & CF_UNSIGNED) {
3550                         if (val < 255) {
3551                             AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3552                             AddCodeLine ("jsr boolult");
3553                         } else {
3554                             AddCodeLine ("cmp #$%02X", (unsigned char)val);
3555                             AddCodeLine ("jsr boolule");
3556                         }
3557                     } else {
3558                         if (val < 127) {
3559                             AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3560                             AddCodeLine ("jsr boollt");
3561                         } else {
3562                             AddCodeLine ("cmp #$%02X", (unsigned char)val);
3563                             AddCodeLine ("jsr boolle");
3564                         }
3565                     }
3566                     return;
3567                 }
3568                 /* FALLTHROUGH */
3569
3570             case CF_INT:
3571                 if (flags & CF_UNSIGNED) {
3572                     unsigned L = GetLocalLabel();
3573                     const char* Name = "boolule";
3574                     if (val < 65535) {
3575                         ++val;
3576                         Name = "boolult";
3577                     }
3578                     AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3579                     AddCodeLine ("bne %s", LocalLabelName (L));
3580                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3581                     g_defcodelabel (L);
3582                     AddCodeLine ("jsr %s", Name);
3583                     return;
3584                 }
3585                 break;
3586
3587             case CF_LONG:
3588                 break;
3589
3590             default:
3591                 typeerror (flags);
3592         }
3593
3594         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3595          * into the normal, non-optimized stuff.
3596          */
3597         g_push (flags & ~CF_CONST, 0);
3598
3599     }
3600
3601     /* Use long way over the stack */
3602     oper (flags, val, ops);
3603 }
3604
3605
3606
3607 void g_gt (unsigned flags, unsigned long val)
3608 /* Test for greater than */
3609 {
3610     static char* ops [12] = {
3611         "tosgt00",      "tosgta0",      "tosgtax",
3612         "tosugt00",     "tosugta0",     "tosugtax",
3613         0,              0,              "tosgteax",
3614         0,              0,              "tosugteax",
3615     };
3616
3617
3618     /* If the right hand side is const, the lhs is not on stack but still
3619      * in the primary register.
3620      */
3621     if (flags & CF_CONST) {
3622
3623         /* > is not very effective on the 6502, so try to convert
3624          * it into >= if the value is in a valid range.
3625          */
3626
3627         /* Look at the type */
3628         switch (flags & CF_TYPE) {
3629
3630             case CF_CHAR:
3631                 if (flags & CF_FORCECHAR) {
3632                     if (flags & CF_UNSIGNED) {
3633                         /* If we have a compare > 0, we will replace it by
3634                          * != 0 here, since both are identical but the latter
3635                          * is easier to optimize.
3636                          */
3637                         if (val == 0) {
3638                             AddCodeLine ("cmp #$%02X", (unsigned char)val);
3639                             AddCodeLine ("jsr boolne");
3640                         } else if (val < 255) {
3641                             AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3642                             AddCodeLine ("jsr booluge");
3643                         } else {
3644                             AddCodeLine ("cmp #$%02X", (unsigned char)val);
3645                             AddCodeLine ("jsr boolugt");
3646                         }
3647                     } else {
3648                         if (val < 127) {
3649                             AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3650                             AddCodeLine ("jsr boolge");
3651                         } else {
3652                             AddCodeLine ("cmp #$%02X", (unsigned char)val);
3653                             AddCodeLine ("jsr boolgt");
3654                         }
3655                     }
3656                     return;
3657                 }
3658                 /* FALLTHROUGH */
3659
3660             case CF_INT:
3661                 if (flags & CF_UNSIGNED) {
3662                     /* If we have a compare > 0, we will replace it by
3663                      * != 0 here, since both are identical but the latter
3664                      * is easier to optimize.
3665                      */
3666                     if (val == 0) {
3667                         AddCodeLine ("stx tmp1");
3668                         AddCodeLine ("ora tmp1");
3669                         AddCodeLine ("jsr boolne");
3670                     } else {
3671                         unsigned L = GetLocalLabel();
3672                         const char* Name = "boolugt";
3673                         if (val < 65535) {
3674                             ++val;
3675                             Name = "booluge";
3676                         }
3677                         AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3678                         AddCodeLine ("bne %s", LocalLabelName (L));
3679                         AddCodeLine ("cmp #$%02X", (unsigned char)val);
3680                         g_defcodelabel (L);
3681                         AddCodeLine ("jsr %s", Name);
3682                     }
3683                     return;
3684                 }
3685                 break;
3686
3687             case CF_LONG:
3688                 break;
3689
3690             default:
3691                 typeerror (flags);
3692         }
3693
3694         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3695          * into the normal, non-optimized stuff.
3696          */
3697         g_push (flags & ~CF_CONST, 0);
3698
3699     }
3700
3701     /* Use long way over the stack */
3702     oper (flags, val, ops);
3703 }
3704
3705
3706
3707 void g_ge (unsigned flags, unsigned long val)
3708 /* Test for greater than or equal to */
3709 {
3710     static char* ops [12] = {
3711         "tosge00",      "tosgea0",      "tosgeax",
3712         "tosuge00",     "tosugea0",     "tosugeax",
3713         0,              0,              "tosgeeax",
3714         0,              0,              "tosugeeax",
3715     };
3716
3717
3718     /* If the right hand side is const, the lhs is not on stack but still
3719      * in the primary register.
3720      */
3721     if (flags & CF_CONST) {
3722
3723         /* Give a warning in some special cases */
3724         if ((flags & CF_UNSIGNED) && val == 0) {
3725             Warning ("Condition is always true");
3726         }
3727
3728         /* Look at the type */
3729         switch (flags & CF_TYPE) {
3730
3731             case CF_CHAR:
3732                 if (flags & CF_FORCECHAR) {
3733                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3734                     if (flags & CF_UNSIGNED) {
3735                         AddCodeLine ("jsr booluge");
3736                     } else {
3737                         AddCodeLine ("jsr boolge");
3738                     }
3739                     return;
3740                 }
3741                 /* FALLTHROUGH */
3742
3743             case CF_INT:
3744                 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3745                     /* If we have a signed compare against zero, we only need to
3746                      * test the high byte.
3747                      */
3748                     AddCodeLine ("txa");
3749                     AddCodeLine ("jsr boolge");
3750                     return;
3751                 }
3752                 /* Direct code only for unsigned data types */
3753                 if (flags & CF_UNSIGNED) {
3754                     unsigned L = GetLocalLabel();
3755                     AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3756                     AddCodeLine ("bne %s", LocalLabelName (L));
3757                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3758                     g_defcodelabel (L);
3759                     AddCodeLine ("jsr booluge");
3760                     return;
3761                 }
3762                 break;
3763
3764             case CF_LONG:
3765                 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3766                     /* If we have a signed compare against zero, we only need to
3767                      * test the high byte.
3768                      */
3769                     AddCodeLine ("lda sreg+1");
3770                     AddCodeLine ("jsr boolge");
3771                     return;
3772                 }
3773                 break;
3774
3775             default:
3776                 typeerror (flags);
3777         }
3778
3779         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3780          * into the normal, non-optimized stuff.
3781          */
3782         g_push (flags & ~CF_CONST, 0);
3783
3784     }
3785
3786     /* Use long way over the stack */
3787     oper (flags, val, ops);
3788 }
3789
3790
3791
3792 /*****************************************************************************/
3793 /*                         Allocating static storage                         */
3794 /*****************************************************************************/
3795
3796
3797
3798 void g_res (unsigned n)
3799 /* Reserve static storage, n bytes */
3800 {
3801     AddDataLine ("\t.res\t%u,$00", n);
3802 }
3803
3804
3805
3806 void g_defdata (unsigned flags, unsigned long val, unsigned offs)
3807 /* Define data with the size given in flags */
3808 {
3809     if (flags & CF_CONST) {
3810
3811         /* Numeric constant */
3812         switch (flags & CF_TYPE) {
3813
3814             case CF_CHAR:
3815                 AddDataLine ("\t.byte\t$%02lX", val & 0xFF);
3816                 break;
3817
3818             case CF_INT:
3819                 AddDataLine ("\t.word\t$%04lX", val & 0xFFFF);
3820                 break;
3821
3822             case CF_LONG:
3823                 AddDataLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
3824                 break;
3825
3826             default:
3827                 typeerror (flags);
3828                 break;
3829
3830         }
3831
3832     } else {
3833
3834         /* Create the correct label name */
3835         const char* Label = GetLabelName (flags, val, offs);
3836
3837         /* Labels are always 16 bit */
3838         AddDataLine ("\t.word\t%s", Label);
3839
3840     }
3841 }
3842
3843
3844
3845 void g_defbytes (const void* Bytes, unsigned Count)
3846 /* Output a row of bytes as a constant */
3847 {
3848     unsigned Chunk;
3849     char Buf [128];
3850     char* B;
3851
3852     /* Cast the buffer pointer */
3853     const unsigned char* Data = (const unsigned char*) Bytes;
3854
3855     /* Output the stuff */
3856     while (Count) {
3857
3858         /* How many go into this line? */
3859         if ((Chunk = Count) > 16) {
3860             Chunk = 16;
3861         }
3862         Count -= Chunk;
3863
3864         /* Output one line */
3865         strcpy (Buf, "\t.byte\t");
3866         B = Buf + 7;
3867         do {
3868             B += sprintf (B, "$%02X", *Data++);
3869             if (--Chunk) {
3870                 *B++ = ',';
3871             }
3872         } while (Chunk);
3873
3874         /* Output the line */
3875         AddDataLine (Buf);
3876     }
3877 }
3878
3879
3880
3881 void g_zerobytes (unsigned n)
3882 /* Output n bytes of data initialized with zero */
3883 {
3884     AddDataLine ("\t.res\t%u,$00", n);
3885 }
3886
3887
3888
3889 /*****************************************************************************/
3890 /*                       User supplied assembler code                        */
3891 /*****************************************************************************/
3892
3893
3894
3895 void g_asmcode (struct StrBuf* B)
3896 /* Output one line of assembler code. */
3897 {
3898     AddCodeLine ("%.*s", SB_GetLen (B), SB_GetConstBuf (B));
3899 }
3900
3901
3902
3903 /*****************************************************************************/
3904 /*                          Inlined known functions                          */
3905 /*****************************************************************************/
3906
3907
3908
3909 void g_strlen (unsigned flags, unsigned long val, unsigned offs)
3910 /* Inline the strlen() function */
3911 {
3912     /* We need a label in both cases */
3913     unsigned label = GetLocalLabel ();
3914
3915     /* Two different encodings */
3916     if (flags & CF_CONST) {
3917
3918         /* The address of the string is constant. Create the correct label name */
3919         char* lbuf = GetLabelName (flags, val, offs);
3920
3921         /* Generate the strlen code */
3922         AddCodeLine ("ldy #$FF");
3923         g_defcodelabel (label);
3924         AddCodeLine ("iny");
3925         AddCodeLine ("lda %s,y", lbuf);
3926         AddCodeLine ("bne %s", LocalLabelName (label));
3927         AddCodeLine ("tax");
3928         AddCodeLine ("tya");
3929
3930     } else {
3931
3932         /* Address not constant but in primary */
3933         if (CodeSizeFactor < 400) {
3934             /* This is too much code, so call strlen instead of inlining */
3935             AddCodeLine ("jsr _strlen");
3936         } else {
3937             /* Inline the function */
3938             AddCodeLine ("sta ptr1");
3939             AddCodeLine ("stx ptr1+1");
3940             AddCodeLine ("ldy #$FF");
3941             g_defcodelabel (label);
3942             AddCodeLine ("iny");
3943             AddCodeLine ("lda (ptr1),y");
3944             AddCodeLine ("bne %s", LocalLabelName (label));
3945             AddCodeLine ("tax");
3946             AddCodeLine ("tya");
3947         }
3948     }
3949 }
3950
3951
3952