]> git.sur5r.net Git - cc65/blob - src/cc65/codegen.c
Added a peephole optimization step for global array accesses
[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                     if (Offs) {
1015                         ldyconst (Offs);
1016                         AddCodeLine ("jsr staxysp");
1017                     } else {
1018                         AddCodeLine ("jsr stax0sp");
1019                     }
1020                 } else {
1021                     if (CPU == CPU_65C02 && Offs == 0) {
1022                         AddCodeLine ("sta (sp)");
1023                         ldyconst (1);
1024                         AddCodeLine ("txa");
1025                         AddCodeLine ("sta (sp),y");
1026                     } else {
1027                         ldyconst (Offs);
1028                         AddCodeLine ("sta (sp),y");
1029                         AddCodeLine ("iny");
1030                         AddCodeLine ("txa");
1031                         AddCodeLine ("sta (sp),y");
1032                     }
1033                 }
1034             }
1035             break;
1036
1037         case CF_LONG:
1038             if (Flags & CF_CONST) {
1039                 g_getimmed (Flags, Val, 0);
1040             }
1041             if (Offs) {
1042                 ldyconst (Offs);
1043                 AddCodeLine ("jsr steaxysp");
1044             } else {
1045                 AddCodeLine ("jsr steax0sp");
1046             }
1047             break;
1048
1049         default:
1050             typeerror (Flags);
1051
1052     }
1053 }
1054
1055
1056
1057 void g_putind (unsigned Flags, unsigned Offs)
1058 /* Store the specified object type in the primary register at the address
1059  * on the top of the stack
1060  */
1061 {
1062     /* We can handle offsets below $100 directly, larger offsets must be added
1063      * to the address. Since a/x is in use, best code is achieved by adding
1064      * just the high byte. Be sure to check if the low byte will overflow while
1065      * while storing.
1066      */
1067     if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
1068
1069         /* Overflow - we need to add the low byte also */
1070         AddCodeLine ("ldy #$00");
1071         AddCodeLine ("clc");
1072         AddCodeLine ("pha");
1073         AddCodeLine ("lda #$%02X", Offs & 0xFF);
1074         AddCodeLine ("adc (sp),y");
1075         AddCodeLine ("sta (sp),y");
1076         AddCodeLine ("iny");
1077         AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1078         AddCodeLine ("adc (sp),y");
1079         AddCodeLine ("sta (sp),y");
1080         AddCodeLine ("pla");
1081
1082         /* Complete address is on stack, new offset is zero */
1083         Offs = 0;
1084
1085     } else if ((Offs & 0xFF00) != 0) {
1086
1087         /* We can just add the high byte */
1088         AddCodeLine ("ldy #$01");
1089         AddCodeLine ("clc");
1090         AddCodeLine ("pha");
1091         AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1092         AddCodeLine ("adc (sp),y");
1093         AddCodeLine ("sta (sp),y");
1094         AddCodeLine ("pla");
1095
1096         /* Offset is now just the low byte */
1097         Offs &= 0x00FF;
1098     }
1099
1100     /* Check the size and determine operation */
1101     switch (Flags & CF_TYPE) {
1102
1103         case CF_CHAR:
1104             ldyconst (Offs);
1105             AddCodeLine ("jsr staspidx");
1106             break;
1107
1108         case CF_INT:
1109             ldyconst (Offs);
1110             AddCodeLine ("jsr staxspidx");
1111             break;
1112
1113         case CF_LONG:
1114             ldyconst (Offs);
1115             AddCodeLine ("jsr steaxspidx");
1116             break;
1117
1118         default:
1119             typeerror (Flags);
1120
1121     }
1122
1123     /* Pop the argument which is always a pointer */
1124     pop (CF_PTR);
1125 }
1126
1127
1128
1129 /*****************************************************************************/
1130 /*                    type conversion and similiar stuff                     */
1131 /*****************************************************************************/
1132
1133
1134
1135 void g_toslong (unsigned flags)
1136 /* Make sure, the value on TOS is a long. Convert if necessary */
1137 {
1138     switch (flags & CF_TYPE) {
1139
1140         case CF_CHAR:
1141         case CF_INT:
1142             if (flags & CF_UNSIGNED) {
1143                 AddCodeLine ("jsr tosulong");
1144             } else {
1145                 AddCodeLine ("jsr toslong");
1146             }
1147             push (CF_INT);
1148             break;
1149
1150         case CF_LONG:
1151             break;
1152
1153         default:
1154             typeerror (flags);
1155     }
1156 }
1157
1158
1159
1160 void g_tosint (unsigned flags)
1161 /* Make sure, the value on TOS is an int. Convert if necessary */
1162 {
1163     switch (flags & CF_TYPE) {
1164
1165         case CF_CHAR:
1166         case CF_INT:
1167             break;
1168
1169         case CF_LONG:
1170             AddCodeLine ("jsr tosint");
1171             pop (CF_INT);
1172             break;
1173
1174         default:
1175             typeerror (flags);
1176     }
1177 }
1178
1179
1180
1181 void g_reglong (unsigned flags)
1182 /* Make sure, the value in the primary register a long. Convert if necessary */
1183 {
1184     switch (flags & CF_TYPE) {
1185
1186         case CF_CHAR:
1187         case CF_INT:
1188             if (flags & CF_UNSIGNED) {
1189                 if (CodeSizeFactor >= 200) {
1190                     ldyconst (0);
1191                     AddCodeLine ("sty sreg");
1192                     AddCodeLine ("sty sreg+1");
1193                 } else {
1194                     AddCodeLine ("jsr axulong");
1195                 }
1196             } else {
1197                 AddCodeLine ("jsr axlong");
1198             }
1199             break;
1200
1201         case CF_LONG:
1202             break;
1203
1204         default:
1205             typeerror (flags);
1206     }
1207 }
1208
1209
1210
1211 unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1212 /* Adjust the integer operands before doing a binary operation. lhs is a flags
1213  * value, that corresponds to the value on TOS, rhs corresponds to the value
1214  * in (e)ax. The return value is the the flags value for the resulting type.
1215  */
1216 {
1217     unsigned ltype, rtype;
1218     unsigned result;
1219
1220     /* Get the type spec from the flags */
1221     ltype = lhs & CF_TYPE;
1222     rtype = rhs & CF_TYPE;
1223
1224     /* Check if a conversion is needed */
1225     if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1226         /* We must promote the primary register to long */
1227         g_reglong (rhs);
1228         /* Get the new rhs type */
1229         rhs = (rhs & ~CF_TYPE) | CF_LONG;
1230         rtype = CF_LONG;
1231     } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1232         /* We must promote the lhs to long */
1233         if (lhs & CF_REG) {
1234             g_reglong (lhs);
1235         } else {
1236             g_toslong (lhs);
1237         }
1238         /* Get the new rhs type */
1239         lhs = (lhs & ~CF_TYPE) | CF_LONG;
1240         ltype = CF_LONG;
1241     }
1242
1243     /* Determine the result type for the operation:
1244      *  - The result is const if both operands are const.
1245      *  - The result is unsigned if one of the operands is unsigned.
1246      *  - The result is long if one of the operands is long.
1247      *  - Otherwise the result is int sized.
1248      */
1249     result = (lhs & CF_CONST) & (rhs & CF_CONST);
1250     result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1251     if (rtype == CF_LONG || ltype == CF_LONG) {
1252         result |= CF_LONG;
1253     } else {
1254         result |= CF_INT;
1255     }
1256     return result;
1257 }
1258
1259
1260
1261 unsigned g_typecast (unsigned lhs, unsigned rhs)
1262 /* Cast the value in the primary register to the operand size that is flagged
1263  * by the lhs value. Return the result value.
1264  */
1265 {
1266     unsigned ltype, rtype;
1267
1268     /* Get the type spec from the flags */
1269     ltype = lhs & CF_TYPE;
1270     rtype = rhs & CF_TYPE;
1271
1272     /* Check if a conversion is needed */
1273     if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1274         /* We must promote the primary register to long */
1275         g_reglong (rhs);
1276     }
1277
1278     /* Do not need any other action. If the left type is int, and the primary
1279      * register is long, it will be automagically truncated. If the right hand
1280      * side is const, it is not located in the primary register and handled by
1281      * the expression parser code.
1282      */
1283
1284     /* Result is const if the right hand side was const */
1285     lhs |= (rhs & CF_CONST);
1286
1287     /* The resulting type is that of the left hand side (that's why you called
1288      * this function :-)
1289      */
1290     return lhs;
1291 }
1292
1293
1294
1295 void g_scale (unsigned flags, long val)
1296 /* Scale the value in the primary register by the given value. If val is positive,
1297  * scale up, is val is negative, scale down. This function is used to scale
1298  * the operands or results of pointer arithmetic by the size of the type, the
1299  * pointer points to.
1300  */
1301 {
1302     int p2;
1303
1304     /* Value may not be zero */
1305     if (val == 0) {
1306         Internal ("Data type has no size");
1307     } else if (val > 0) {
1308
1309         /* Scale up */
1310         if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
1311
1312             /* Factor is 2, 4, 8 and 16, use special function */
1313             switch (flags & CF_TYPE) {
1314
1315                 case CF_CHAR:
1316                     if (flags & CF_FORCECHAR) {
1317                         while (p2--) {
1318                             AddCodeLine ("asl a");
1319                         }
1320                         break;
1321                     }
1322                     /* FALLTHROUGH */
1323
1324                 case CF_INT:
1325                     if (CodeSizeFactor >= (p2+1)*130U) {
1326                         AddCodeLine ("stx tmp1");
1327                         while (p2--) {
1328                             AddCodeLine ("asl a");
1329                             AddCodeLine ("rol tmp1");
1330                         }
1331                         AddCodeLine ("ldx tmp1");
1332                     } else {
1333                         if (flags & CF_UNSIGNED) {
1334                             AddCodeLine ("jsr shlax%d", p2);
1335                         } else {
1336                             AddCodeLine ("jsr aslax%d", p2);
1337                         }
1338                     }
1339                     break;
1340
1341                 case CF_LONG:
1342                     if (flags & CF_UNSIGNED) {
1343                         AddCodeLine ("jsr shleax%d", p2);
1344                     } else {
1345                         AddCodeLine ("jsr asleax%d", p2);
1346                     }
1347                     break;
1348
1349                 default:
1350                     typeerror (flags);
1351
1352             }
1353
1354         } else if (val != 1) {
1355
1356             /* Use a multiplication instead */
1357             g_mul (flags | CF_CONST, val);
1358
1359         }
1360
1361     } else {
1362
1363         /* Scale down */
1364         val = -val;
1365         if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
1366
1367             /* Factor is 2, 4, 8 and 16 use special function */
1368             switch (flags & CF_TYPE) {
1369
1370                 case CF_CHAR:
1371                     if (flags & CF_FORCECHAR) {
1372                         if (flags & CF_UNSIGNED) {
1373                             while (p2--) {
1374                                 AddCodeLine ("lsr a");
1375                             }
1376                             break;
1377                         } else if (p2 <= 2) {
1378                             AddCodeLine ("cmp #$80");
1379                             AddCodeLine ("ror a");
1380                             break;
1381                         }
1382                     }
1383                     /* FALLTHROUGH */
1384
1385                 case CF_INT:
1386                     if (flags & CF_UNSIGNED) {
1387                         if (CodeSizeFactor >= (p2+1)*130U) {
1388                             AddCodeLine ("stx tmp1");
1389                             while (p2--) {
1390                                 AddCodeLine ("lsr tmp1");
1391                                 AddCodeLine ("ror a");
1392                             }
1393                             AddCodeLine ("ldx tmp1");
1394                         } else {
1395                             AddCodeLine ("jsr lsrax%d", p2);
1396                         }
1397                     } else {
1398                         if (CodeSizeFactor >= (p2+1)*150U) {
1399                             AddCodeLine ("stx tmp1");
1400                             while (p2--) {
1401                                 AddCodeLine ("cpx #$80");
1402                                 AddCodeLine ("ror tmp1");
1403                                 AddCodeLine ("ror a");
1404                             }
1405                             AddCodeLine ("ldx tmp1");
1406                         } else {
1407                             AddCodeLine ("jsr asrax%d", p2);
1408                         }
1409                     }
1410                     break;
1411
1412                 case CF_LONG:
1413                     if (flags & CF_UNSIGNED) {
1414                         AddCodeLine ("jsr lsreax%d", p2);
1415                     } else {
1416                         AddCodeLine ("jsr asreax%d", p2);
1417                     }
1418                     break;
1419
1420                 default:
1421                     typeerror (flags);
1422
1423             }
1424
1425         } else if (val != 1) {
1426
1427             /* Use a division instead */
1428             g_div (flags | CF_CONST, val);
1429
1430         }
1431     }
1432 }
1433
1434
1435
1436 /*****************************************************************************/
1437 /*              Adds and subs of variables fix a fixed address               */
1438 /*****************************************************************************/
1439
1440
1441
1442 void g_addlocal (unsigned flags, int offs)
1443 /* Add a local variable to ax */
1444 {
1445     unsigned L;
1446
1447     /* Correct the offset and check it */
1448     offs -= oursp;
1449     CheckLocalOffs (offs);
1450
1451     switch (flags & CF_TYPE) {
1452
1453         case CF_CHAR:
1454             L = GetLocalLabel();
1455             AddCodeLine ("ldy #$%02X", offs & 0xFF);
1456             AddCodeLine ("clc");
1457             AddCodeLine ("adc (sp),y");
1458             AddCodeLine ("bcc %s", LocalLabelName (L));
1459             AddCodeLine ("inx");
1460             g_defcodelabel (L);
1461             break;
1462
1463         case CF_INT:
1464             AddCodeLine ("ldy #$%02X", offs & 0xFF);
1465             AddCodeLine ("clc");
1466             AddCodeLine ("adc (sp),y");
1467             AddCodeLine ("pha");
1468             AddCodeLine ("txa");
1469             AddCodeLine ("iny");
1470             AddCodeLine ("adc (sp),y");
1471             AddCodeLine ("tax");
1472             AddCodeLine ("pla");
1473             break;
1474
1475         case CF_LONG:
1476             /* Do it the old way */
1477             g_push (flags, 0);
1478             g_getlocal (flags, offs);
1479             g_add (flags, 0);
1480             break;
1481
1482         default:
1483             typeerror (flags);
1484
1485     }
1486 }
1487
1488
1489
1490 void g_addstatic (unsigned flags, unsigned long label, unsigned offs)
1491 /* Add a static variable to ax */
1492 {
1493     unsigned L;
1494
1495     /* Create the correct label name */
1496     char* lbuf = GetLabelName (flags, label, offs);
1497
1498     switch (flags & CF_TYPE) {
1499
1500         case CF_CHAR:
1501             L = GetLocalLabel();
1502             AddCodeLine ("clc");
1503             AddCodeLine ("adc %s", lbuf);
1504             AddCodeLine ("bcc %s", LocalLabelName (L));
1505             AddCodeLine ("inx");
1506             g_defcodelabel (L);
1507             break;
1508
1509         case CF_INT:
1510             AddCodeLine ("clc");
1511             AddCodeLine ("adc %s", lbuf);
1512             AddCodeLine ("tay");
1513             AddCodeLine ("txa");
1514             AddCodeLine ("adc %s+1", lbuf);
1515             AddCodeLine ("tax");
1516             AddCodeLine ("tya");
1517             break;
1518
1519         case CF_LONG:
1520             /* Do it the old way */
1521             g_push (flags, 0);
1522             g_getstatic (flags, label, offs);
1523             g_add (flags, 0);
1524             break;
1525
1526         default:
1527             typeerror (flags);
1528
1529     }
1530 }
1531
1532
1533
1534 /*****************************************************************************/
1535 /*             Compares of ax with a variable with fixed address             */
1536 /*****************************************************************************/
1537
1538
1539
1540 void g_cmplocal (unsigned flags, int offs)
1541 /* Compare a local variable to ax */
1542 {
1543     Internal ("g_cmplocal not implemented");
1544 }
1545
1546
1547
1548 void g_cmpstatic (unsigned flags, unsigned label, unsigned offs)
1549 /* Compare a static variable to ax */
1550 {
1551     Internal ("g_cmpstatic not implemented");
1552 }
1553
1554
1555
1556 /*****************************************************************************/
1557 /*                           Special op= functions                           */
1558 /*****************************************************************************/
1559
1560
1561
1562 void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
1563                     unsigned long val)
1564 /* Emit += for a static variable */
1565 {
1566     /* Create the correct label name */
1567     char* lbuf = GetLabelName (flags, label, offs);
1568
1569     /* Check the size and determine operation */
1570     switch (flags & CF_TYPE) {
1571
1572         case CF_CHAR:
1573             if (flags & CF_FORCECHAR) {
1574                 AddCodeLine ("ldx #$00");
1575                 if (flags & CF_CONST) {
1576                     if (val == 1) {
1577                         AddCodeLine ("inc %s", lbuf);
1578                         AddCodeLine ("lda %s", lbuf);
1579                     } else {
1580                         AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1581                         AddCodeLine ("clc");
1582                         AddCodeLine ("adc %s", lbuf);
1583                         AddCodeLine ("sta %s", lbuf);
1584                     }
1585                 } else {
1586                     AddCodeLine ("clc");
1587                     AddCodeLine ("adc %s", lbuf);
1588                     AddCodeLine ("sta %s", lbuf);
1589                 }
1590                 if ((flags & CF_UNSIGNED) == 0) {
1591                     unsigned L = GetLocalLabel();
1592                     AddCodeLine ("bpl %s", LocalLabelName (L));
1593                     AddCodeLine ("dex");
1594                     g_defcodelabel (L);
1595                 }
1596                 break;
1597             }
1598             /* FALLTHROUGH */
1599
1600         case CF_INT:
1601             if (flags & CF_CONST) {
1602                 if (val == 1) {
1603                     unsigned L = GetLocalLabel ();
1604                     AddCodeLine ("inc %s", lbuf);
1605                     AddCodeLine ("bne %s", LocalLabelName (L));
1606                     AddCodeLine ("inc %s+1", lbuf);
1607                     g_defcodelabel (L);
1608                     AddCodeLine ("lda %s", lbuf);               /* Hmmm... */
1609                     AddCodeLine ("ldx %s+1", lbuf);
1610                 } else {
1611                     AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1612                     AddCodeLine ("clc");
1613                     AddCodeLine ("adc %s", lbuf);
1614                     AddCodeLine ("sta %s", lbuf);
1615                     if (val < 0x100) {
1616                         unsigned L = GetLocalLabel ();
1617                         AddCodeLine ("bcc %s", LocalLabelName (L));
1618                         AddCodeLine ("inc %s+1", lbuf);
1619                         g_defcodelabel (L);
1620                         AddCodeLine ("ldx %s+1", lbuf);
1621                     } else {
1622                         AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1623                         AddCodeLine ("adc %s+1", lbuf);
1624                         AddCodeLine ("sta %s+1", lbuf);
1625                         AddCodeLine ("tax");
1626                         AddCodeLine ("lda %s", lbuf);
1627                     }
1628                 }
1629             } else {
1630                 AddCodeLine ("clc");
1631                 AddCodeLine ("adc %s", lbuf);
1632                 AddCodeLine ("sta %s", lbuf);
1633                 AddCodeLine ("txa");
1634                 AddCodeLine ("adc %s+1", lbuf);
1635                 AddCodeLine ("sta %s+1", lbuf);
1636                 AddCodeLine ("tax");
1637                 AddCodeLine ("lda %s", lbuf);
1638             }
1639             break;
1640
1641         case CF_LONG:
1642             if (flags & CF_CONST) {
1643                 if (val < 0x100) {
1644                     AddCodeLine ("ldy #<(%s)", lbuf);
1645                     AddCodeLine ("sty ptr1");
1646                     AddCodeLine ("ldy #>(%s+1)", lbuf);
1647                     if (val == 1) {
1648                         AddCodeLine ("jsr laddeq1");
1649                     } else {
1650                         AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1651                         AddCodeLine ("jsr laddeqa");
1652                     }
1653                 } else {
1654                     g_getstatic (flags, label, offs);
1655                     g_inc (flags, val);
1656                     g_putstatic (flags, label, offs);
1657                 }
1658             } else {
1659                 AddCodeLine ("ldy #<(%s)", lbuf);
1660                 AddCodeLine ("sty ptr1");
1661                 AddCodeLine ("ldy #>(%s+1)", lbuf);
1662                 AddCodeLine ("jsr laddeq");
1663             }
1664             break;
1665
1666         default:
1667             typeerror (flags);
1668     }
1669 }
1670
1671
1672
1673 void g_addeqlocal (unsigned flags, int offs, unsigned long val)
1674 /* Emit += for a local variable */
1675 {
1676     /* Calculate the true offset, check it, load it into Y */
1677     offs -= oursp;
1678     CheckLocalOffs (offs);
1679
1680     /* Check the size and determine operation */
1681     switch (flags & CF_TYPE) {
1682
1683         case CF_CHAR:
1684             if (flags & CF_FORCECHAR) {
1685                 ldyconst (offs);
1686                 AddCodeLine ("ldx #$00");
1687                 if (flags & CF_CONST) {
1688                     AddCodeLine ("clc");
1689                     AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1690                     AddCodeLine ("adc (sp),y");
1691                     AddCodeLine ("sta (sp),y");
1692                 } else {
1693                     AddCodeLine ("clc");
1694                     AddCodeLine ("adc (sp),y");
1695                     AddCodeLine ("sta (sp),y");
1696                 }
1697                 if ((flags & CF_UNSIGNED) == 0) {
1698                     unsigned L = GetLocalLabel();
1699                     AddCodeLine ("bpl %s", LocalLabelName (L));
1700                     AddCodeLine ("dex");
1701                     g_defcodelabel (L);
1702                 }
1703                 break;
1704             }
1705             /* FALLTHROUGH */
1706
1707         case CF_INT:
1708             if (flags & CF_CONST) {
1709                 g_getimmed (flags, val, 0);
1710             }
1711             ldyconst (offs);
1712             AddCodeLine ("jsr addeqysp");
1713             break;
1714
1715         case CF_LONG:
1716             if (flags & CF_CONST) {
1717                 g_getimmed (flags, val, 0);
1718             }
1719             if (offs == 0) {
1720                 AddCodeLine ("jsr laddeq0sp");
1721             } else {
1722                 ldyconst (offs);
1723                 AddCodeLine ("jsr laddeqysp");
1724             }
1725             break;
1726
1727         default:
1728             typeerror (flags);
1729     }
1730 }
1731
1732
1733
1734 void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
1735 /* Emit += for the location with address in ax */
1736 {
1737     /* If the offset is too large for a byte register, add the high byte
1738      * of the offset to the primary. Beware: We need a special correction
1739      * if the offset in the low byte will overflow in the operation.
1740      */
1741     offs = MakeByteOffs (flags, offs);
1742
1743     /* Check the size and determine operation */
1744     switch (flags & CF_TYPE) {
1745
1746         case CF_CHAR:
1747             AddCodeLine ("sta ptr1");
1748             AddCodeLine ("stx ptr1+1");
1749             AddCodeLine ("ldy #$%02X", offs);
1750             AddCodeLine ("ldx #$00");
1751             AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1752             AddCodeLine ("clc");
1753             AddCodeLine ("adc (ptr1),y");
1754             AddCodeLine ("sta (ptr1),y");
1755             break;
1756
1757         case CF_INT:
1758             if (CodeSizeFactor >= 200) {
1759                 /* Lots of code, use only if size is not important */
1760                 AddCodeLine ("sta ptr1");
1761                 AddCodeLine ("stx ptr1+1");
1762                 AddCodeLine ("ldy #$%02X", offs);
1763                 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1764                 AddCodeLine ("clc");
1765                 AddCodeLine ("adc (ptr1),y");
1766                 AddCodeLine ("sta (ptr1),y");
1767                 AddCodeLine ("pha");
1768                 AddCodeLine ("iny");
1769                 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1770                 AddCodeLine ("adc (ptr1),y");
1771                 AddCodeLine ("sta (ptr1),y");
1772                 AddCodeLine ("tax");
1773                 AddCodeLine ("pla");
1774                 break;
1775             }
1776             /* FALL THROUGH */
1777
1778         case CF_LONG:
1779             AddCodeLine ("jsr pushax");         /* Push the address */
1780             push (CF_PTR);                      /* Correct the internal sp */
1781             g_getind (flags, offs);             /* Fetch the value */
1782             g_inc (flags, val);                 /* Increment value in primary */
1783             g_putind (flags, offs);             /* Store the value back */
1784             break;
1785
1786         default:
1787             typeerror (flags);
1788     }
1789 }
1790
1791
1792
1793 void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
1794                     unsigned long val)
1795 /* Emit -= for a static variable */
1796 {
1797     /* Create the correct label name */
1798     char* lbuf = GetLabelName (flags, label, offs);
1799
1800     /* Check the size and determine operation */
1801     switch (flags & CF_TYPE) {
1802
1803         case CF_CHAR:
1804             if (flags & CF_FORCECHAR) {
1805                 AddCodeLine ("ldx #$00");
1806                 if (flags & CF_CONST) {
1807                     if (val == 1) {
1808                         AddCodeLine ("dec %s", lbuf);
1809                         AddCodeLine ("lda %s", lbuf);
1810                     } else {
1811                         AddCodeLine ("sec");
1812                         AddCodeLine ("lda %s", lbuf);
1813                         AddCodeLine ("sbc #$%02X", (int)(val & 0xFF));
1814                         AddCodeLine ("sta %s", lbuf);
1815                     }
1816                 } else {
1817                     AddCodeLine ("sec");
1818                     AddCodeLine ("sta tmp1");
1819                     AddCodeLine ("lda %s", lbuf);
1820                     AddCodeLine ("sbc tmp1");
1821                     AddCodeLine ("sta %s", lbuf);
1822                 }
1823                 if ((flags & CF_UNSIGNED) == 0) {
1824                     unsigned L = GetLocalLabel();
1825                     AddCodeLine ("bpl %s", LocalLabelName (L));
1826                     AddCodeLine ("dex");
1827                     g_defcodelabel (L);
1828                 }
1829                 break;
1830             }
1831             /* FALLTHROUGH */
1832
1833         case CF_INT:
1834             AddCodeLine ("sec");
1835             if (flags & CF_CONST) {
1836                 AddCodeLine ("lda %s", lbuf);
1837                 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1838                 AddCodeLine ("sta %s", lbuf);
1839                 if (val < 0x100) {
1840                     unsigned L = GetLocalLabel ();
1841                     AddCodeLine ("bcs %s", LocalLabelName (L));
1842                     AddCodeLine ("dec %s+1", lbuf);
1843                     g_defcodelabel (L);
1844                     AddCodeLine ("ldx %s+1", lbuf);
1845                 } else {
1846                     AddCodeLine ("lda %s+1", lbuf);
1847                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
1848                     AddCodeLine ("sta %s+1", lbuf);
1849                     AddCodeLine ("tax");
1850                     AddCodeLine ("lda %s", lbuf);
1851                 }
1852             } else {
1853                 AddCodeLine ("sta tmp1");
1854                 AddCodeLine ("lda %s", lbuf);
1855                 AddCodeLine ("sbc tmp1");
1856                 AddCodeLine ("sta %s", lbuf);
1857                 AddCodeLine ("stx tmp1");
1858                 AddCodeLine ("lda %s+1", lbuf);
1859                 AddCodeLine ("sbc tmp1");
1860                 AddCodeLine ("sta %s+1", lbuf);
1861                 AddCodeLine ("tax");
1862                 AddCodeLine ("lda %s", lbuf);
1863             }
1864             break;
1865
1866         case CF_LONG:
1867             if (flags & CF_CONST) {
1868                 if (val < 0x100) {
1869                     AddCodeLine ("ldy #<(%s)", lbuf);
1870                     AddCodeLine ("sty ptr1");
1871                     AddCodeLine ("ldy #>(%s+1)", lbuf);
1872                     if (val == 1) {
1873                         AddCodeLine ("jsr lsubeq1");
1874                     } else {
1875                         AddCodeLine ("lda #$%02X", (unsigned char)val);
1876                         AddCodeLine ("jsr lsubeqa");
1877                     }
1878                 } else {
1879                     g_getstatic (flags, label, offs);
1880                     g_dec (flags, val);
1881                     g_putstatic (flags, label, offs);
1882                 }
1883             } else {
1884                 AddCodeLine ("ldy #<(%s)", lbuf);
1885                 AddCodeLine ("sty ptr1");
1886                 AddCodeLine ("ldy #>(%s+1)", lbuf);
1887                 AddCodeLine ("jsr lsubeq");
1888             }
1889             break;
1890
1891         default:
1892             typeerror (flags);
1893     }
1894 }
1895
1896
1897
1898 void g_subeqlocal (unsigned flags, int offs, unsigned long val)
1899 /* Emit -= for a local variable */
1900 {
1901     /* Calculate the true offset, check it, load it into Y */
1902     offs -= oursp;
1903     CheckLocalOffs (offs);
1904
1905     /* Check the size and determine operation */
1906     switch (flags & CF_TYPE) {
1907
1908         case CF_CHAR:
1909             if (flags & CF_FORCECHAR) {
1910                 ldyconst (offs);
1911                 AddCodeLine ("ldx #$00");
1912                 AddCodeLine ("sec");
1913                 if (flags & CF_CONST) {
1914                     AddCodeLine ("lda (sp),y");
1915                     AddCodeLine ("sbc #$%02X", (unsigned char)val);
1916                 } else {
1917                     AddCodeLine ("sta tmp1");
1918                     AddCodeLine ("lda (sp),y");
1919                     AddCodeLine ("sbc tmp1");
1920                 }
1921                 AddCodeLine ("sta (sp),y");
1922                 if ((flags & CF_UNSIGNED) == 0) {
1923                     unsigned L = GetLocalLabel();
1924                     AddCodeLine ("bpl %s", LocalLabelName (L));
1925                     AddCodeLine ("dex");
1926                     g_defcodelabel (L);
1927                 }
1928                 break;
1929             }
1930             /* FALLTHROUGH */
1931
1932         case CF_INT:
1933             if (flags & CF_CONST) {
1934                 g_getimmed (flags, val, 0);
1935             }
1936             if (offs == 0) {
1937                 AddCodeLine ("jsr subeq0sp");
1938             } else {
1939                 ldyconst (offs);
1940                 AddCodeLine ("jsr subeqysp");
1941             }
1942             break;
1943
1944         case CF_LONG:
1945             if (flags & CF_CONST) {
1946                 g_getimmed (flags, val, 0);
1947             }
1948             if (offs == 0) {
1949                 AddCodeLine ("jsr lsubeq0sp");
1950             } else {
1951                 ldyconst (offs);
1952                 AddCodeLine ("jsr lsubeqysp");
1953             }
1954             break;
1955
1956         default:
1957             typeerror (flags);
1958     }
1959 }
1960
1961
1962
1963 void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
1964 /* Emit -= for the location with address in ax */
1965 {
1966     /* If the offset is too large for a byte register, add the high byte
1967      * of the offset to the primary. Beware: We need a special correction
1968      * if the offset in the low byte will overflow in the operation.
1969      */
1970     offs = MakeByteOffs (flags, offs);
1971
1972     /* Check the size and determine operation */
1973     switch (flags & CF_TYPE) {
1974
1975         case CF_CHAR:
1976             AddCodeLine ("sta ptr1");
1977             AddCodeLine ("stx ptr1+1");
1978             AddCodeLine ("ldy #$%02X", offs);
1979             AddCodeLine ("ldx #$00");
1980             AddCodeLine ("lda (ptr1),y");
1981             AddCodeLine ("sec");
1982             AddCodeLine ("sbc #$%02X", (unsigned char)val);
1983             AddCodeLine ("sta (ptr1),y");
1984             break;
1985
1986         case CF_INT:
1987             if (CodeSizeFactor >= 200) {
1988                 /* Lots of code, use only if size is not important */
1989                 AddCodeLine ("sta ptr1");
1990                 AddCodeLine ("stx ptr1+1");
1991                 AddCodeLine ("ldy #$%02X", offs);
1992                 AddCodeLine ("lda (ptr1),y");
1993                 AddCodeLine ("sec");
1994                 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1995                 AddCodeLine ("sta (ptr1),y");
1996                 AddCodeLine ("pha");
1997                 AddCodeLine ("iny");
1998                 AddCodeLine ("lda (ptr1),y");
1999                 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
2000                 AddCodeLine ("sta (ptr1),y");
2001                 AddCodeLine ("tax");
2002                 AddCodeLine ("pla");
2003                 break;
2004             }
2005             /* FALL THROUGH */
2006
2007         case CF_LONG:
2008             AddCodeLine ("jsr pushax");         /* Push the address */
2009             push (CF_PTR);                      /* Correct the internal sp */
2010             g_getind (flags, offs);             /* Fetch the value */
2011             g_dec (flags, val);                 /* Increment value in primary */
2012             g_putind (flags, offs);             /* Store the value back */
2013             break;
2014
2015         default:
2016             typeerror (flags);
2017     }
2018 }
2019
2020
2021
2022 /*****************************************************************************/
2023 /*                 Add a variable address to the value in ax                 */
2024 /*****************************************************************************/
2025
2026
2027
2028 void g_addaddr_local (unsigned flags, int offs)
2029 /* Add the address of a local variable to ax */
2030 {
2031     unsigned L = 0;
2032
2033     /* Add the offset */
2034     offs -= oursp;
2035     if (offs != 0) {
2036         /* We cannot address more then 256 bytes of locals anyway */
2037         L = GetLocalLabel();
2038         CheckLocalOffs (offs);
2039         AddCodeLine ("clc");
2040         AddCodeLine ("adc #$%02X", offs & 0xFF);
2041         /* Do also skip the CLC insn below */
2042         AddCodeLine ("bcc %s", LocalLabelName (L));
2043         AddCodeLine ("inx");
2044     }
2045
2046     /* Add the current stackpointer value */
2047     AddCodeLine ("clc");
2048     if (L != 0) {
2049         /* Label was used above */
2050         g_defcodelabel (L);
2051     }
2052     AddCodeLine ("adc sp");
2053     AddCodeLine ("tay");
2054     AddCodeLine ("txa");
2055     AddCodeLine ("adc sp+1");
2056     AddCodeLine ("tax");
2057     AddCodeLine ("tya");
2058 }
2059
2060
2061
2062 void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs)
2063 /* Add the address of a static variable to ax */
2064 {
2065     /* Create the correct label name */
2066     char* lbuf = GetLabelName (flags, label, offs);
2067
2068     /* Add the address to the current ax value */
2069     AddCodeLine ("clc");
2070     AddCodeLine ("adc #<(%s)", lbuf);
2071     AddCodeLine ("tay");
2072     AddCodeLine ("txa");
2073     AddCodeLine ("adc #>(%s)", lbuf);
2074     AddCodeLine ("tax");
2075     AddCodeLine ("tya");
2076 }
2077
2078
2079
2080 /*****************************************************************************/
2081 /*                                                                           */
2082 /*****************************************************************************/
2083
2084
2085
2086 void g_save (unsigned flags)
2087 /* Copy primary register to hold register. */
2088 {
2089     /* Check the size and determine operation */
2090     switch (flags & CF_TYPE) {
2091
2092         case CF_CHAR:
2093             if (flags & CF_FORCECHAR) {
2094                 AddCodeLine ("pha");
2095                 break;
2096             }
2097             /* FALLTHROUGH */
2098
2099         case CF_INT:
2100             AddCodeLine ("sta regsave");
2101             AddCodeLine ("stx regsave+1");
2102             break;
2103
2104         case CF_LONG:
2105             AddCodeLine ("jsr saveeax");
2106             break;
2107
2108         default:
2109             typeerror (flags);
2110     }
2111 }
2112
2113
2114
2115 void g_restore (unsigned flags)
2116 /* Copy hold register to primary. */
2117 {
2118     /* Check the size and determine operation */
2119     switch (flags & CF_TYPE) {
2120
2121         case CF_CHAR:
2122             if (flags & CF_FORCECHAR) {
2123                 AddCodeLine ("pla");
2124                 break;
2125             }
2126             /* FALLTHROUGH */
2127
2128         case CF_INT:
2129             AddCodeLine ("lda regsave");
2130             AddCodeLine ("ldx regsave+1");
2131             break;
2132
2133         case CF_LONG:
2134             AddCodeLine ("jsr resteax");
2135             break;
2136
2137         default:
2138             typeerror (flags);
2139     }
2140 }
2141
2142
2143
2144 void g_cmp (unsigned flags, unsigned long val)
2145 /* Immidiate compare. The primary register will not be changed, Z flag
2146  * will be set.
2147  */
2148 {
2149     unsigned L;
2150
2151     /* Check the size and determine operation */
2152     switch (flags & CF_TYPE) {
2153
2154         case CF_CHAR:
2155             if (flags & CF_FORCECHAR) {
2156                 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2157                 break;
2158             }
2159             /* FALLTHROUGH */
2160
2161         case CF_INT:
2162             L = GetLocalLabel();
2163             AddCodeLine ("cmp #$%02X", (unsigned char)val);
2164             AddCodeLine ("bne %s", LocalLabelName (L));
2165             AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
2166             g_defcodelabel (L);
2167             break;
2168
2169         case CF_LONG:
2170             Internal ("g_cmp: Long compares not implemented");
2171             break;
2172
2173         default:
2174             typeerror (flags);
2175     }
2176 }
2177
2178
2179
2180 static void oper (unsigned flags, unsigned long val, char** subs)
2181 /* Encode a binary operation. subs is a pointer to four groups of three
2182  * strings:
2183  *      0-2     --> Operate on ints
2184  *      3-5     --> Operate on unsigneds
2185  *      6-8     --> Operate on longs
2186  *      9-11    --> Operate on unsigned longs
2187  *
2188  * The first subroutine names in each string group is used to encode an
2189  * operation with a zero constant, the second to encode an operation with
2190  * a 8 bit constant, and the third is used in all other cases.
2191  */
2192 {
2193     unsigned offs;
2194
2195     /* Determine the offset into the array */
2196     offs = (flags & CF_UNSIGNED)? 3 : 0;
2197     switch (flags & CF_TYPE) {
2198         case CF_CHAR:
2199         case CF_INT:
2200             break;
2201
2202         case CF_LONG:
2203             offs += 6;
2204             break;
2205
2206         default:
2207             typeerror (flags);
2208     }
2209
2210     /* Encode the operation */
2211     if (flags & CF_CONST) {
2212         /* Constant value given */
2213         if (val == 0 && subs [offs+0]) {
2214             /* Special case: constant with value zero */
2215             AddCodeLine ("jsr %s", subs [offs+0]);
2216         } else if (val < 0x100 && subs [offs+1]) {
2217             /* Special case: constant with high byte zero */
2218             ldaconst (val);             /* Load low byte */
2219             AddCodeLine ("jsr %s", subs [offs+1]);
2220         } else {
2221             /* Others: arbitrary constant value */
2222             g_getimmed (flags, val, 0);                 /* Load value */
2223             AddCodeLine ("jsr %s", subs [offs+2]);
2224         }
2225     } else {
2226         /* Value not constant (is already in (e)ax) */
2227         AddCodeLine ("jsr %s", subs [offs+2]);
2228     }
2229
2230     /* The operation will pop it's argument */
2231     pop (flags);
2232 }
2233
2234
2235
2236 void g_test (unsigned flags)
2237 /* Test the value in the primary and set the condition codes */
2238 {
2239     switch (flags & CF_TYPE) {
2240
2241         case CF_CHAR:
2242             if (flags & CF_FORCECHAR) {
2243                 AddCodeLine ("tax");
2244                 break;
2245             }
2246             /* FALLTHROUGH */
2247
2248         case CF_INT:
2249             AddCodeLine ("stx tmp1");
2250             AddCodeLine ("ora tmp1");
2251             break;
2252
2253         case CF_LONG:
2254             if (flags & CF_UNSIGNED) {
2255                 AddCodeLine ("jsr utsteax");
2256             } else {
2257                 AddCodeLine ("jsr tsteax");
2258             }
2259             break;
2260
2261         default:
2262             typeerror (flags);
2263
2264     }
2265 }
2266
2267
2268
2269 void g_push (unsigned flags, unsigned long val)
2270 /* Push the primary register or a constant value onto the stack */
2271 {
2272     unsigned char hi;
2273
2274     if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
2275
2276         /* We have a constant 8 or 16 bit value */
2277         if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
2278
2279             /* Handle as 8 bit value */
2280             if (CodeSizeFactor >= 165 || val > 2) {
2281                 ldaconst (val);
2282                 AddCodeLine ("jsr pusha");
2283             } else {
2284                 AddCodeLine ("jsr pushc%d", (int) val);
2285             }
2286
2287         } else {
2288
2289             /* Handle as 16 bit value */
2290             hi = (unsigned char) (val >> 8);
2291             if (val <= 7) {
2292                 AddCodeLine ("jsr push%u", (unsigned) val);
2293             } else if (hi == 0 || hi == 0xFF) {
2294                 /* Use special function */
2295                 ldaconst (val);
2296                 AddCodeLine ("jsr %s", (hi == 0)? "pusha0" : "pushaFF");
2297             } else {
2298                 /* Long way ... */
2299                 g_getimmed (flags, val, 0);
2300                 AddCodeLine ("jsr pushax");
2301             }
2302         }
2303
2304     } else {
2305
2306         /* Value is not 16 bit or not constant */
2307         if (flags & CF_CONST) {
2308             /* Constant 32 bit value, load into eax */
2309             g_getimmed (flags, val, 0);
2310         }
2311
2312         /* Push the primary register */
2313         switch (flags & CF_TYPE) {
2314
2315             case CF_CHAR:
2316                 if (flags & CF_FORCECHAR) {
2317                     /* Handle as char */
2318                     AddCodeLine ("jsr pusha");
2319                     break;
2320                 }
2321                 /* FALL THROUGH */
2322             case CF_INT:
2323                 AddCodeLine ("jsr pushax");
2324                 break;
2325
2326             case CF_LONG:
2327                 AddCodeLine ("jsr pusheax");
2328                 break;
2329
2330             default:
2331                 typeerror (flags);
2332
2333         }
2334
2335     }
2336
2337     /* Adjust the stack offset */
2338     push (flags);
2339 }
2340
2341
2342
2343 void g_swap (unsigned flags)
2344 /* Swap the primary register and the top of the stack. flags give the type
2345  * of *both* values (must have same size).
2346  */
2347 {
2348     switch (flags & CF_TYPE) {
2349
2350         case CF_CHAR:
2351         case CF_INT:
2352             AddCodeLine ("jsr swapstk");
2353             break;
2354
2355         case CF_LONG:
2356             AddCodeLine ("jsr swapestk");
2357             break;
2358
2359         default:
2360             typeerror (flags);
2361
2362     }
2363 }
2364
2365
2366
2367 void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
2368 /* Call the specified subroutine name */
2369 {
2370     if ((Flags & CF_FIXARGC) == 0) {
2371         /* Pass the argument count */
2372         ldyconst (ArgSize);
2373     }
2374     AddCodeLine ("jsr _%s", Label);
2375     oursp += ArgSize;           /* callee pops args */
2376 }
2377
2378
2379
2380 void g_callind (unsigned Flags, unsigned ArgSize)
2381 /* Call subroutine with address in AX */
2382 {
2383     if ((Flags & CF_FIXARGC) == 0) {
2384         /* Pass arg count */
2385         ldyconst (ArgSize);
2386     }
2387     AddCodeLine ("jsr callax"); /* do the call */
2388     oursp += ArgSize;                   /* callee pops args */
2389 }
2390
2391
2392
2393 void g_jump (unsigned Label)
2394 /* Jump to specified internal label number */
2395 {
2396     AddCodeLine ("jmp %s", LocalLabelName (Label));
2397 }
2398
2399
2400
2401 void g_switch (unsigned Flags)
2402 /* Output switch statement preamble */
2403 {
2404     switch (Flags & CF_TYPE) {
2405
2406         case CF_CHAR:
2407         case CF_INT:
2408             AddCodeLine ("jsr switch");
2409             break;
2410
2411         case CF_LONG:
2412             AddCodeLine ("jsr lswitch");
2413             break;
2414
2415         default:
2416             typeerror (Flags);
2417
2418     }
2419 }
2420
2421
2422
2423 void g_case (unsigned flags, unsigned label, unsigned long val)
2424 /* Create table code for one case selector */
2425 {
2426     switch (flags & CF_TYPE) {
2427
2428         case CF_CHAR:
2429         case CF_INT:
2430             AddCodeLine (".word $%04X, %s",
2431                          (unsigned)(val & 0xFFFF),
2432                          LocalLabelName (label));
2433             break;
2434
2435         case CF_LONG:
2436             AddCodeLine (".dword $%08lX", val);
2437             AddCodeLine (".word %s", LocalLabelName (label));
2438             break;
2439
2440         default:
2441             typeerror (flags);
2442
2443     }
2444 }
2445
2446
2447
2448 void g_truejump (unsigned flags, unsigned label)
2449 /* Jump to label if zero flag clear */
2450 {
2451     AddCodeLine ("jne %s", LocalLabelName (label));
2452 }
2453
2454
2455
2456 void g_falsejump (unsigned flags, unsigned label)
2457 /* Jump to label if zero flag set */
2458 {
2459     AddCodeLine ("jeq %s", LocalLabelName (label));
2460 }
2461
2462
2463
2464 static void mod_internal (int k, char* verb1, char* verb2)
2465 {
2466     if (k <= 8) {
2467         AddCodeLine ("jsr %ssp%c", verb1, k + '0');
2468     } else {
2469         CheckLocalOffs (k);
2470         ldyconst (k);
2471         AddCodeLine ("jsr %ssp", verb2);
2472     }
2473 }
2474
2475
2476
2477 void g_space (int space)
2478 /* Create or drop space on the stack */
2479 {
2480     if (space < 0) {
2481         mod_internal (-space, "inc", "addy");
2482     } else if (space > 0) {
2483         mod_internal (space, "dec", "suby");
2484     }
2485 }
2486
2487
2488
2489 void g_cstackcheck (void)
2490 /* Check for a C stack overflow */
2491 {
2492     AddCodeLine ("jsr cstkchk");
2493 }
2494
2495
2496
2497 void g_stackcheck (void)
2498 /* Check for a stack overflow */
2499 {
2500     AddCodeLine ("jsr stkchk");
2501 }
2502
2503
2504
2505 void g_add (unsigned flags, unsigned long val)
2506 /* Primary = TOS + Primary */
2507 {
2508     static char* ops [12] = {
2509         0,              "tosadda0",     "tosaddax",
2510         0,              "tosadda0",     "tosaddax",
2511         0,              0,              "tosaddeax",
2512         0,              0,              "tosaddeax",
2513     };
2514
2515     if (flags & CF_CONST) {
2516         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2517         g_push (flags & ~CF_CONST, 0);
2518     }
2519     oper (flags, val, ops);
2520 }
2521
2522
2523
2524 void g_sub (unsigned flags, unsigned long val)
2525 /* Primary = TOS - Primary */
2526 {
2527     static char* ops [12] = {
2528         0,              "tossuba0",     "tossubax",
2529         0,              "tossuba0",     "tossubax",
2530         0,              0,              "tossubeax",
2531         0,              0,              "tossubeax",
2532     };
2533
2534     if (flags & CF_CONST) {
2535         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2536         g_push (flags & ~CF_CONST, 0);
2537     }
2538     oper (flags, val, ops);
2539 }
2540
2541
2542
2543 void g_rsub (unsigned flags, unsigned long val)
2544 /* Primary = Primary - TOS */
2545 {
2546     static char* ops [12] = {
2547         0,              "tosrsuba0",    "tosrsubax",
2548         0,              "tosrsuba0",    "tosrsubax",
2549         0,              0,              "tosrsubeax",
2550         0,              0,              "tosrsubeax",
2551     };
2552     oper (flags, val, ops);
2553 }
2554
2555
2556
2557 void g_mul (unsigned flags, unsigned long val)
2558 /* Primary = TOS * Primary */
2559 {
2560     static char* ops [12] = {
2561         0,              "tosmula0",     "tosmulax",
2562         0,              "tosumula0",    "tosumulax",
2563         0,              0,              "tosmuleax",
2564         0,              0,              "tosumuleax",
2565     };
2566
2567     int p2;
2568
2569     /* Do strength reduction if the value is constant and a power of two */
2570     if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2571         /* Generate a shift instead */
2572         g_asl (flags, p2);
2573         return;
2574     }
2575
2576     /* If the right hand side is const, the lhs is not on stack but still
2577      * in the primary register.
2578      */
2579     if (flags & CF_CONST) {
2580
2581         switch (flags & CF_TYPE) {
2582
2583             case CF_CHAR:
2584                 if (flags & CF_FORCECHAR) {
2585                     /* Handle some special cases */
2586                     switch (val) {
2587
2588                         case 3:
2589                             AddCodeLine ("sta tmp1");
2590                             AddCodeLine ("asl a");
2591                             AddCodeLine ("clc");
2592                             AddCodeLine ("adc tmp1");
2593                             return;
2594
2595                         case 5:
2596                             AddCodeLine ("sta tmp1");
2597                             AddCodeLine ("asl a");
2598                             AddCodeLine ("asl a");
2599                             AddCodeLine ("clc");
2600                             AddCodeLine ("adc tmp1");
2601                             return;
2602
2603                         case 10:
2604                             AddCodeLine ("sta tmp1");
2605                             AddCodeLine ("asl a");
2606                             AddCodeLine ("asl a");
2607                             AddCodeLine ("clc");
2608                             AddCodeLine ("adc tmp1");
2609                             AddCodeLine ("asl a");
2610                             return;
2611                     }
2612                 }
2613                 /* FALLTHROUGH */
2614
2615             case CF_INT:
2616                 break;
2617
2618             case CF_LONG:
2619                 break;
2620
2621             default:
2622                 typeerror (flags);
2623         }
2624
2625         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2626          * into the normal, non-optimized stuff.
2627          */
2628         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2629         g_push (flags & ~CF_CONST, 0);
2630
2631     }
2632
2633     /* Use long way over the stack */
2634     oper (flags, val, ops);
2635 }
2636
2637
2638
2639 void g_div (unsigned flags, unsigned long val)
2640 /* Primary = TOS / Primary */
2641 {
2642     static char* ops [12] = {
2643         0,              "tosdiva0",     "tosdivax",
2644         0,              "tosudiva0",    "tosudivax",
2645         0,              0,              "tosdiveax",
2646         0,              0,              "tosudiveax",
2647     };
2648
2649     /* Do strength reduction if the value is constant and a power of two */
2650     int p2;
2651     if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2652         /* Generate a shift instead */
2653         g_asr (flags, p2);
2654     } else {
2655         /* Generate a division */
2656         if (flags & CF_CONST) {
2657             /* lhs is not on stack */
2658             flags &= ~CF_FORCECHAR;     /* Handle chars as ints */
2659             g_push (flags & ~CF_CONST, 0);
2660         }
2661         oper (flags, val, ops);
2662     }
2663 }
2664
2665
2666
2667 void g_mod (unsigned flags, unsigned long val)
2668 /* Primary = TOS % Primary */
2669 {
2670     static char* ops [12] = {
2671         0,              "tosmoda0",     "tosmodax",
2672         0,              "tosumoda0",    "tosumodax",
2673         0,              0,              "tosmodeax",
2674         0,              0,              "tosumodeax",
2675     };
2676     int p2;
2677
2678     /* Check if we can do some cost reduction */
2679     if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2680         /* We can do that with an AND operation */
2681         g_and (flags, val - 1);
2682     } else {
2683         /* Do it the hard way... */
2684         if (flags & CF_CONST) {
2685             /* lhs is not on stack */
2686             flags &= ~CF_FORCECHAR;     /* Handle chars as ints */
2687             g_push (flags & ~CF_CONST, 0);
2688         }
2689         oper (flags, val, ops);
2690     }
2691 }
2692
2693
2694
2695 void g_or (unsigned flags, unsigned long val)
2696 /* Primary = TOS | Primary */
2697 {
2698     static char* ops [12] = {
2699         0,              "tosora0",      "tosorax",
2700         0,              "tosora0",      "tosorax",
2701         0,              0,              "tosoreax",
2702         0,              0,              "tosoreax",
2703     };
2704
2705     /* If the right hand side is const, the lhs is not on stack but still
2706      * in the primary register.
2707      */
2708     if (flags & CF_CONST) {
2709
2710         switch (flags & CF_TYPE) {
2711
2712             case CF_CHAR:
2713                 if (flags & CF_FORCECHAR) {
2714                     if ((val & 0xFF) != 0xFF) {
2715                         AddCodeLine ("ora #$%02X", (unsigned char)val);
2716                     }
2717                     return;
2718                 }
2719                 /* FALLTHROUGH */
2720
2721             case CF_INT:
2722                 if (val <= 0xFF) {
2723                     AddCodeLine ("ora #$%02X", (unsigned char)val);
2724                     return;
2725                 }
2726                 break;
2727
2728             case CF_LONG:
2729                 if (val <= 0xFF) {
2730                     AddCodeLine ("ora #$%02X", (unsigned char)val);
2731                     return;
2732                 }
2733                 break;
2734
2735             default:
2736                 typeerror (flags);
2737         }
2738
2739         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2740          * into the normal, non-optimized stuff.
2741          */
2742         g_push (flags & ~CF_CONST, 0);
2743
2744     }
2745
2746     /* Use long way over the stack */
2747     oper (flags, val, ops);
2748 }
2749
2750
2751
2752 void g_xor (unsigned flags, unsigned long val)
2753 /* Primary = TOS ^ Primary */
2754 {
2755     static char* ops [12] = {
2756         0,              "tosxora0",     "tosxorax",
2757         0,              "tosxora0",     "tosxorax",
2758         0,              0,              "tosxoreax",
2759         0,              0,              "tosxoreax",
2760     };
2761
2762
2763     /* If the right hand side is const, the lhs is not on stack but still
2764      * in the primary register.
2765      */
2766     if (flags & CF_CONST) {
2767
2768         switch (flags & CF_TYPE) {
2769
2770             case CF_CHAR:
2771                 if (flags & CF_FORCECHAR) {
2772                     if ((val & 0xFF) != 0) {
2773                         AddCodeLine ("eor #$%02X", (unsigned char)val);
2774                     }
2775                     return;
2776                 }
2777                 /* FALLTHROUGH */
2778
2779             case CF_INT:
2780                 if (val <= 0xFF) {
2781                     if (val != 0) {
2782                         AddCodeLine ("eor #$%02X", (unsigned char)val);
2783                     }
2784                     return;
2785                 } else if ((val & 0xFF) == 0) {
2786                     AddCodeLine ("pha");
2787                     AddCodeLine ("txa");
2788                     AddCodeLine ("eor #$%02X", (unsigned char)(val >> 8));
2789                     AddCodeLine ("tax");
2790                     AddCodeLine ("pla");
2791                     return;
2792                 }
2793                 break;
2794
2795             case CF_LONG:
2796                 if (val <= 0xFF) {
2797                     if (val != 0) {
2798                         AddCodeLine ("eor #$%02X", (unsigned char)val);
2799                     }
2800                     return;
2801                 }
2802                 break;
2803
2804             default:
2805                 typeerror (flags);
2806         }
2807
2808         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2809          * into the normal, non-optimized stuff.
2810          */
2811         g_push (flags & ~CF_CONST, 0);
2812
2813     }
2814
2815     /* Use long way over the stack */
2816     oper (flags, val, ops);
2817 }
2818
2819
2820
2821 void g_and (unsigned flags, unsigned long val)
2822 /* Primary = TOS & Primary */
2823 {
2824     static char* ops [12] = {
2825         0,              "tosanda0",     "tosandax",
2826         0,              "tosanda0",     "tosandax",
2827         0,              0,              "tosandeax",
2828         0,              0,              "tosandeax",
2829     };
2830
2831     /* If the right hand side is const, the lhs is not on stack but still
2832      * in the primary register.
2833      */
2834     if (flags & CF_CONST) {
2835
2836         switch (flags & CF_TYPE) {
2837
2838             case CF_CHAR:
2839                 if (flags & CF_FORCECHAR) {
2840                     AddCodeLine ("and #$%02X", (unsigned char)val);
2841                     return;
2842                 }
2843                 /* FALLTHROUGH */
2844             case CF_INT:
2845                 if ((val & 0xFFFF) != 0xFFFF) {
2846                     if (val <= 0xFF) {
2847                         ldxconst (0);
2848                         if (val == 0) {
2849                             ldaconst (0);
2850                         } else if (val != 0xFF) {
2851                             AddCodeLine ("and #$%02X", (unsigned char)val);
2852                         }
2853                     } else if ((val & 0xFF00) == 0xFF00) {
2854                         AddCodeLine ("and #$%02X", (unsigned char)val);
2855                     } else if ((val & 0x00FF) == 0x0000) {
2856                         AddCodeLine ("txa");
2857                         AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2858                         AddCodeLine ("tax");
2859                         ldaconst (0);
2860                     } else {
2861                         AddCodeLine ("tay");
2862                         AddCodeLine ("txa");
2863                         AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2864                         AddCodeLine ("tax");
2865                         AddCodeLine ("tya");
2866                         if ((val & 0x00FF) != 0x00FF) {
2867                             AddCodeLine ("and #$%02X", (unsigned char)val);
2868                         }
2869                     }
2870                 }
2871                 return;
2872
2873             case CF_LONG:
2874                 if (val <= 0xFF) {
2875                     ldxconst (0);
2876                     AddCodeLine ("stx sreg+1");
2877                     AddCodeLine ("stx sreg");
2878                     if ((val & 0xFF) != 0xFF) {
2879                          AddCodeLine ("and #$%02X", (unsigned char)val);
2880                     }
2881                     return;
2882                 } else if (val == 0xFF00) {
2883                     ldaconst (0);
2884                     AddCodeLine ("sta sreg+1");
2885                     AddCodeLine ("sta sreg");
2886                     return;
2887                 }
2888                 break;
2889
2890             default:
2891                 typeerror (flags);
2892         }
2893
2894         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2895          * into the normal, non-optimized stuff.
2896          */
2897         g_push (flags & ~CF_CONST, 0);
2898
2899     }
2900
2901     /* Use long way over the stack */
2902     oper (flags, val, ops);
2903 }
2904
2905
2906
2907 void g_asr (unsigned flags, unsigned long val)
2908 /* Primary = TOS >> Primary */
2909 {
2910     static char* ops [12] = {
2911         0,              "tosasra0",     "tosasrax",
2912         0,              "tosshra0",     "tosshrax",
2913         0,              0,              "tosasreax",
2914         0,              0,              "tosshreax",
2915     };
2916
2917     /* If the right hand side is const, the lhs is not on stack but still
2918      * in the primary register.
2919      */
2920     if (flags & CF_CONST) {
2921
2922         switch (flags & CF_TYPE) {
2923
2924             case CF_CHAR:
2925             case CF_INT:
2926                 if (val >= 1 && val <= 4) {
2927                     if (flags & CF_UNSIGNED) {
2928                         AddCodeLine ("jsr shrax%ld", val);
2929                     } else {
2930                         AddCodeLine ("jsr asrax%ld", val);
2931                     }
2932                     return;
2933                 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2934                     AddCodeLine ("txa");
2935                     ldxconst (0);
2936                     return;
2937                 }
2938                 break;
2939
2940             case CF_LONG:
2941                 if (val >= 1 && val <= 4) {
2942                     if (flags & CF_UNSIGNED) {
2943                         AddCodeLine ("jsr shreax%ld", val);
2944                     } else {
2945                         AddCodeLine ("jsr asreax%ld", val);
2946                     }
2947                     return;
2948                 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2949                     AddCodeLine ("txa");
2950                     AddCodeLine ("ldx sreg");
2951                     AddCodeLine ("ldy sreg+1");
2952                     AddCodeLine ("sty sreg");
2953                     AddCodeLine ("ldy #$00");
2954                     AddCodeLine ("sty sreg+1");
2955                     return;
2956                 } else if (val == 16) {
2957                     AddCodeLine ("ldy #$00");
2958                     AddCodeLine ("ldx sreg+1");
2959                     if ((flags & CF_UNSIGNED) == 0) {
2960                         unsigned L = GetLocalLabel();
2961                         AddCodeLine ("bpl %s", LocalLabelName (L));
2962                         AddCodeLine ("dey");
2963                         g_defcodelabel (L);
2964                     }
2965                     AddCodeLine ("lda sreg");
2966                     AddCodeLine ("sty sreg+1");
2967                     AddCodeLine ("sty sreg");
2968                     return;
2969                 }
2970                 break;
2971
2972             default:
2973                 typeerror (flags);
2974         }
2975
2976         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2977          * into the normal, non-optimized stuff.
2978          */
2979         g_push (flags & ~CF_CONST, 0);
2980
2981     }
2982
2983     /* Use long way over the stack */
2984     oper (flags, val, ops);
2985 }
2986
2987
2988
2989 void g_asl (unsigned flags, unsigned long val)
2990 /* Primary = TOS << Primary */
2991 {
2992     static char* ops [12] = {
2993         0,              "tosasla0",     "tosaslax",
2994         0,              "tosshla0",     "tosshlax",
2995         0,              0,              "tosasleax",
2996         0,              0,              "tosshleax",
2997     };
2998
2999
3000     /* If the right hand side is const, the lhs is not on stack but still
3001      * in the primary register.
3002      */
3003     if (flags & CF_CONST) {
3004
3005         switch (flags & CF_TYPE) {
3006
3007             case CF_CHAR:
3008             case CF_INT:
3009                 if (val >= 1 && val <= 4) {
3010                     if (flags & CF_UNSIGNED) {
3011                         AddCodeLine ("jsr shlax%ld", val);
3012                     } else {
3013                         AddCodeLine ("jsr aslax%ld", val);
3014                     }
3015                     return;
3016                 } else if (val == 8) {
3017                     AddCodeLine ("tax");
3018                     AddCodeLine ("lda #$00");
3019                     return;
3020                 }
3021                 break;
3022
3023             case CF_LONG:
3024                 if (val >= 1 && val <= 4) {
3025                     if (flags & CF_UNSIGNED) {
3026                         AddCodeLine ("jsr shleax%ld", val);
3027                     } else {
3028                         AddCodeLine ("jsr asleax%ld", val);
3029                     }
3030                     return;
3031                 } else if (val == 8) {
3032                     AddCodeLine ("ldy sreg");
3033                     AddCodeLine ("sty sreg+1");
3034                     AddCodeLine ("stx sreg");
3035                     AddCodeLine ("tax");
3036                     AddCodeLine ("lda #$00");
3037                     return;
3038                 } else if (val == 16) {
3039                     AddCodeLine ("stx sreg+1");
3040                     AddCodeLine ("sta sreg");
3041                     AddCodeLine ("lda #$00");
3042                     AddCodeLine ("tax");
3043                     return;
3044                 }
3045                 break;
3046
3047             default:
3048                 typeerror (flags);
3049         }
3050
3051         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3052          * into the normal, non-optimized stuff.
3053          */
3054         g_push (flags & ~CF_CONST, 0);
3055
3056     }
3057
3058     /* Use long way over the stack */
3059     oper (flags, val, ops);
3060 }
3061
3062
3063
3064 void g_neg (unsigned flags)
3065 /* Primary = -Primary */
3066 {
3067     switch (flags & CF_TYPE) {
3068
3069         case CF_CHAR:
3070         case CF_INT:
3071             AddCodeLine ("jsr negax");
3072             break;
3073
3074         case CF_LONG:
3075             AddCodeLine ("jsr negeax");
3076             break;
3077
3078         default:
3079             typeerror (flags);
3080     }
3081 }
3082
3083
3084
3085 void g_bneg (unsigned flags)
3086 /* Primary = !Primary */
3087 {
3088     switch (flags & CF_TYPE) {
3089
3090         case CF_CHAR:
3091             AddCodeLine ("jsr bnega");
3092             break;
3093
3094         case CF_INT:
3095             AddCodeLine ("jsr bnegax");
3096             break;
3097
3098         case CF_LONG:
3099             AddCodeLine ("jsr bnegeax");
3100             break;
3101
3102         default:
3103             typeerror (flags);
3104     }
3105 }
3106
3107
3108
3109 void g_com (unsigned flags)
3110 /* Primary = ~Primary */
3111 {
3112     switch (flags & CF_TYPE) {
3113
3114         case CF_CHAR:
3115         case CF_INT:
3116             AddCodeLine ("jsr complax");
3117             break;
3118
3119         case CF_LONG:
3120             AddCodeLine ("jsr compleax");
3121             break;
3122
3123         default:
3124             typeerror (flags);
3125     }
3126 }
3127
3128
3129
3130 void g_inc (unsigned flags, unsigned long val)
3131 /* Increment the primary register by a given number */
3132 {
3133     /* Don't inc by zero */
3134     if (val == 0) {
3135         return;
3136     }
3137
3138     /* Generate code for the supported types */
3139     flags &= ~CF_CONST;
3140     switch (flags & CF_TYPE) {
3141
3142         case CF_CHAR:
3143             if (flags & CF_FORCECHAR) {
3144                 if (CPU == CPU_65C02 && val <= 2) {
3145                     while (val--) {
3146                         AddCodeLine ("ina");
3147                     }
3148                 } else {
3149                     AddCodeLine ("clc");
3150                     AddCodeLine ("adc #$%02X", (unsigned char)val);
3151                 }
3152                 break;
3153             }
3154             /* FALLTHROUGH */
3155
3156         case CF_INT:
3157             if (CPU == CPU_65C02 && val == 1) {
3158                 unsigned L = GetLocalLabel();
3159                 AddCodeLine ("ina");
3160                 AddCodeLine ("bne %s", LocalLabelName (L));
3161                 AddCodeLine ("inx");
3162                 g_defcodelabel (L);
3163             } else if (CodeSizeFactor < 200) {
3164                 /* Use jsr calls */
3165                 if (val <= 8) {
3166                     AddCodeLine ("jsr incax%lu", val);
3167                 } else if (val <= 255) {
3168                     ldyconst (val);
3169                     AddCodeLine ("jsr incaxy");
3170                 } else {
3171                     g_add (flags | CF_CONST, val);
3172                 }
3173             } else {
3174                 /* Inline the code */
3175                 if (val < 0x300) {
3176                     if ((val & 0xFF) != 0) {
3177                         unsigned L = GetLocalLabel();
3178                         AddCodeLine ("clc");
3179                         AddCodeLine ("adc #$%02X", (unsigned char) val);
3180                         AddCodeLine ("bcc %s", LocalLabelName (L));
3181                         AddCodeLine ("inx");
3182                         g_defcodelabel (L);
3183                     }
3184                     if (val >= 0x100) {
3185                         AddCodeLine ("inx");
3186                     }
3187                     if (val >= 0x200) {
3188                         AddCodeLine ("inx");
3189                     }
3190                 } else {
3191                     AddCodeLine ("clc");
3192                     if ((val & 0xFF) != 0) {
3193                         AddCodeLine ("adc #$%02X", (unsigned char) val);
3194                     }
3195                     AddCodeLine ("pha");
3196                     AddCodeLine ("txa");
3197                     AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3198                     AddCodeLine ("tax");
3199                     AddCodeLine ("pla");
3200                 }
3201             }
3202             break;
3203
3204         case CF_LONG:
3205             if (val <= 255) {
3206                 ldyconst (val);
3207                 AddCodeLine ("jsr inceaxy");
3208             } else {
3209                 g_add (flags | CF_CONST, val);
3210             }
3211             break;
3212
3213         default:
3214             typeerror (flags);
3215
3216     }
3217 }
3218
3219
3220
3221 void g_dec (unsigned flags, unsigned long val)
3222 /* Decrement the primary register by a given number */
3223 {
3224     /* Don't dec by zero */
3225     if (val == 0) {
3226         return;
3227     }
3228
3229     /* Generate code for the supported types */
3230     flags &= ~CF_CONST;
3231     switch (flags & CF_TYPE) {
3232
3233         case CF_CHAR:
3234             if (flags & CF_FORCECHAR) {
3235                 if (CPU == CPU_65C02 && val <= 2) {
3236                     while (val--) {
3237                         AddCodeLine ("dea");
3238                     }
3239                 } else {
3240                     AddCodeLine ("sec");
3241                     AddCodeLine ("sbc #$%02X", (unsigned char)val);
3242                 }
3243                 break;
3244             }
3245             /* FALLTHROUGH */
3246
3247         case CF_INT:
3248             if (CodeSizeFactor < 200) {
3249                 /* Use subroutines */
3250                 if (val <= 8) {
3251                     AddCodeLine ("jsr decax%d", (int) val);
3252                 } else if (val <= 255) {
3253                     ldyconst (val);
3254                     AddCodeLine ("jsr decaxy");
3255                 } else {
3256                     g_sub (flags | CF_CONST, val);
3257                 }
3258             } else {
3259                 /* Inline the code */
3260                 if (val < 0x300) {
3261                     if ((val & 0xFF) != 0) {
3262                         unsigned L = GetLocalLabel();
3263                         AddCodeLine ("sec");
3264                         AddCodeLine ("sbc #$%02X", (unsigned char) val);
3265                         AddCodeLine ("bcs %s", LocalLabelName (L));
3266                         AddCodeLine ("dex");
3267                         g_defcodelabel (L);
3268                     }
3269                     if (val >= 0x100) {
3270                         AddCodeLine ("dex");
3271                     }
3272                     if (val >= 0x200) {
3273                         AddCodeLine ("dex");
3274                     }
3275                 } else {
3276                     AddCodeLine ("sec");
3277                     if ((val & 0xFF) != 0) {
3278                         AddCodeLine ("sbc #$%02X", (unsigned char) val);
3279                     }
3280                     AddCodeLine ("pha");
3281                     AddCodeLine ("txa");
3282                     AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3283                     AddCodeLine ("tax");
3284                     AddCodeLine ("pla");
3285                 }
3286             }
3287             break;
3288
3289         case CF_LONG:
3290             if (val <= 255) {
3291                 ldyconst (val);
3292                 AddCodeLine ("jsr deceaxy");
3293             } else {
3294                 g_sub (flags | CF_CONST, val);
3295             }
3296             break;
3297
3298         default:
3299             typeerror (flags);
3300
3301     }
3302 }
3303
3304
3305
3306 /*
3307  * Following are the conditional operators. They compare the TOS against
3308  * the primary and put a literal 1 in the primary if the condition is
3309  * true, otherwise they clear the primary register
3310  */
3311
3312
3313
3314 void g_eq (unsigned flags, unsigned long val)
3315 /* Test for equal */
3316 {
3317     static char* ops [12] = {
3318         "toseq00",      "toseqa0",      "toseqax",
3319         "toseq00",      "toseqa0",      "toseqax",
3320         0,              0,              "toseqeax",
3321         0,              0,              "toseqeax",
3322     };
3323
3324     unsigned L;
3325
3326     /* If the right hand side is const, the lhs is not on stack but still
3327      * in the primary register.
3328      */
3329     if (flags & CF_CONST) {
3330
3331         switch (flags & CF_TYPE) {
3332
3333             case CF_CHAR:
3334                 if (flags & CF_FORCECHAR) {
3335                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3336                     AddCodeLine ("jsr booleq");
3337                     return;
3338                 }
3339                 /* FALLTHROUGH */
3340
3341             case CF_INT:
3342                 L = GetLocalLabel();
3343                 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3344                 AddCodeLine ("bne %s", LocalLabelName (L));
3345                 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3346                 g_defcodelabel (L);
3347                 AddCodeLine ("jsr booleq");
3348                 return;
3349
3350             case CF_LONG:
3351                 break;
3352
3353             default:
3354                 typeerror (flags);
3355         }
3356
3357         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3358          * into the normal, non-optimized stuff.
3359          */
3360         g_push (flags & ~CF_CONST, 0);
3361
3362     }
3363
3364     /* Use long way over the stack */
3365     oper (flags, val, ops);
3366 }
3367
3368
3369
3370 void g_ne (unsigned flags, unsigned long val)
3371 /* Test for not equal */
3372 {
3373     static char* ops [12] = {
3374         "tosne00",      "tosnea0",      "tosneax",
3375         "tosne00",      "tosnea0",      "tosneax",
3376         0,              0,              "tosneeax",
3377         0,              0,              "tosneeax",
3378     };
3379
3380     unsigned L;
3381
3382     /* If the right hand side is const, the lhs is not on stack but still
3383      * in the primary register.
3384      */
3385     if (flags & CF_CONST) {
3386
3387         switch (flags & CF_TYPE) {
3388
3389             case CF_CHAR:
3390                 if (flags & CF_FORCECHAR) {
3391                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3392                     AddCodeLine ("jsr boolne");
3393                     return;
3394                 }
3395                 /* FALLTHROUGH */
3396
3397             case CF_INT:
3398                 L = GetLocalLabel();
3399                 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3400                 AddCodeLine ("bne %s", LocalLabelName (L));
3401                 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3402                 g_defcodelabel (L);
3403                 AddCodeLine ("jsr boolne");
3404                 return;
3405
3406             case CF_LONG:
3407                 break;
3408
3409             default:
3410                 typeerror (flags);
3411         }
3412
3413         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3414          * into the normal, non-optimized stuff.
3415          */
3416         g_push (flags & ~CF_CONST, 0);
3417
3418     }
3419
3420     /* Use long way over the stack */
3421     oper (flags, val, ops);
3422 }
3423
3424
3425
3426 void g_lt (unsigned flags, unsigned long val)
3427 /* Test for less than */
3428 {
3429     static char* ops [12] = {
3430         "toslt00",      "toslta0",      "tosltax",
3431         "tosult00",     "tosulta0",     "tosultax",
3432         0,              0,              "toslteax",
3433         0,              0,              "tosulteax",
3434     };
3435
3436     /* If the right hand side is const, the lhs is not on stack but still
3437      * in the primary register.
3438      */
3439     if (flags & CF_CONST) {
3440
3441         /* Give a warning in some special cases */
3442         if ((flags & CF_UNSIGNED) && val == 0) {
3443             Warning ("Condition is never true");
3444         }
3445
3446         /* Look at the type */
3447         switch (flags & CF_TYPE) {
3448
3449             case CF_CHAR:
3450                 if (flags & CF_FORCECHAR) {
3451                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3452                     if (flags & CF_UNSIGNED) {
3453                         AddCodeLine ("jsr boolult");
3454                     } else {
3455                         AddCodeLine ("jsr boollt");
3456                     }
3457                     return;
3458                 }
3459                 /* FALLTHROUGH */
3460
3461             case CF_INT:
3462                 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3463                     /* If we have a signed compare against zero, we only need to
3464                      * test the high byte.
3465                      */
3466                     AddCodeLine ("txa");
3467                     AddCodeLine ("jsr boollt");
3468                     return;
3469                 }
3470                 /* Direct code only for unsigned data types */
3471                 if (flags & CF_UNSIGNED) {
3472                     unsigned L = GetLocalLabel();
3473                     AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3474                     AddCodeLine ("bne %s", LocalLabelName (L));
3475                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3476                     g_defcodelabel (L);
3477                     AddCodeLine ("jsr boolult");
3478                     return;
3479                 }
3480                 break;
3481
3482             case CF_LONG:
3483                 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3484                     /* If we have a signed compare against zero, we only need to
3485                      * test the high byte.
3486                      */
3487                     AddCodeLine ("lda sreg+1");
3488                     AddCodeLine ("jsr boollt");
3489                     return;
3490                 }
3491                 break;
3492
3493             default:
3494                 typeerror (flags);
3495         }
3496
3497         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3498          * into the normal, non-optimized stuff.
3499          */
3500         g_push (flags & ~CF_CONST, 0);
3501
3502     }
3503
3504     /* Use long way over the stack */
3505     oper (flags, val, ops);
3506 }
3507
3508
3509
3510 void g_le (unsigned flags, unsigned long val)
3511 /* Test for less than or equal to */
3512 {
3513     static char* ops [12] = {
3514         "tosle00",      "toslea0",      "tosleax",
3515         "tosule00",     "tosulea0",     "tosuleax",
3516         0,              0,              "tosleeax",
3517         0,              0,              "tosuleeax",
3518     };
3519
3520
3521     /* If the right hand side is const, the lhs is not on stack but still
3522      * in the primary register.
3523      */
3524     if (flags & CF_CONST) {
3525
3526         /* <= is not very effective on the 6502, so try to convert
3527          * it into < if the value is in a valid range.
3528          */
3529
3530         /* Look at the type */
3531         switch (flags & CF_TYPE) {
3532
3533             case CF_CHAR:
3534                 if (flags & CF_FORCECHAR) {
3535                     if (flags & CF_UNSIGNED) {
3536                         if (val < 255) {
3537                             AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3538                             AddCodeLine ("jsr boolult");
3539                         } else {
3540                             AddCodeLine ("cmp #$%02X", (unsigned char)val);
3541                             AddCodeLine ("jsr boolule");
3542                         }
3543                     } else {
3544                         if (val < 127) {
3545                             AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3546                             AddCodeLine ("jsr boollt");
3547                         } else {
3548                             AddCodeLine ("cmp #$%02X", (unsigned char)val);
3549                             AddCodeLine ("jsr boolle");
3550                         }
3551                     }
3552                     return;
3553                 }
3554                 /* FALLTHROUGH */
3555
3556             case CF_INT:
3557                 if (flags & CF_UNSIGNED) {
3558                     unsigned L = GetLocalLabel();
3559                     const char* Name = "boolule";
3560                     if (val < 65535) {
3561                         ++val;
3562                         Name = "boolult";
3563                     }
3564                     AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3565                     AddCodeLine ("bne %s", LocalLabelName (L));
3566                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3567                     g_defcodelabel (L);
3568                     AddCodeLine ("jsr %s", Name);
3569                     return;
3570                 }
3571                 break;
3572
3573             case CF_LONG:
3574                 break;
3575
3576             default:
3577                 typeerror (flags);
3578         }
3579
3580         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3581          * into the normal, non-optimized stuff.
3582          */
3583         g_push (flags & ~CF_CONST, 0);
3584
3585     }
3586
3587     /* Use long way over the stack */
3588     oper (flags, val, ops);
3589 }
3590
3591
3592
3593 void g_gt (unsigned flags, unsigned long val)
3594 /* Test for greater than */
3595 {
3596     static char* ops [12] = {
3597         "tosgt00",      "tosgta0",      "tosgtax",
3598         "tosugt00",     "tosugta0",     "tosugtax",
3599         0,              0,              "tosgteax",
3600         0,              0,              "tosugteax",
3601     };
3602
3603
3604     /* If the right hand side is const, the lhs is not on stack but still
3605      * in the primary register.
3606      */
3607     if (flags & CF_CONST) {
3608
3609         /* > is not very effective on the 6502, so try to convert
3610          * it into >= if the value is in a valid range.
3611          */
3612
3613         /* Look at the type */
3614         switch (flags & CF_TYPE) {
3615
3616             case CF_CHAR:
3617                 if (flags & CF_FORCECHAR) {
3618                     if (flags & CF_UNSIGNED) {
3619                         /* If we have a compare > 0, we will replace it by
3620                          * != 0 here, since both are identical but the latter
3621                          * is easier to optimize.
3622                          */
3623                         if (val == 0) {
3624                             AddCodeLine ("cmp #$%02X", (unsigned char)val);
3625                             AddCodeLine ("jsr boolne");
3626                         } else if (val < 255) {
3627                             AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3628                             AddCodeLine ("jsr booluge");
3629                         } else {
3630                             AddCodeLine ("cmp #$%02X", (unsigned char)val);
3631                             AddCodeLine ("jsr boolugt");
3632                         }
3633                     } else {
3634                         if (val < 127) {
3635                             AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3636                             AddCodeLine ("jsr boolge");
3637                         } else {
3638                             AddCodeLine ("cmp #$%02X", (unsigned char)val);
3639                             AddCodeLine ("jsr boolgt");
3640                         }
3641                     }
3642                     return;
3643                 }
3644                 /* FALLTHROUGH */
3645
3646             case CF_INT:
3647                 if (flags & CF_UNSIGNED) {
3648                     /* If we have a compare > 0, we will replace it by
3649                      * != 0 here, since both are identical but the latter
3650                      * is easier to optimize.
3651                      */
3652                     if (val == 0) {
3653                         AddCodeLine ("stx tmp1");
3654                         AddCodeLine ("ora tmp1");
3655                         AddCodeLine ("jsr boolne");
3656                     } else {
3657                         unsigned L = GetLocalLabel();
3658                         const char* Name = "boolugt";
3659                         if (val < 65535) {
3660                             ++val;
3661                             Name = "booluge";
3662                         }
3663                         AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3664                         AddCodeLine ("bne %s", LocalLabelName (L));
3665                         AddCodeLine ("cmp #$%02X", (unsigned char)val);
3666                         g_defcodelabel (L);
3667                         AddCodeLine ("jsr %s", Name);
3668                     }
3669                     return;
3670                 }
3671                 break;
3672
3673             case CF_LONG:
3674                 break;
3675
3676             default:
3677                 typeerror (flags);
3678         }
3679
3680         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3681          * into the normal, non-optimized stuff.
3682          */
3683         g_push (flags & ~CF_CONST, 0);
3684
3685     }
3686
3687     /* Use long way over the stack */
3688     oper (flags, val, ops);
3689 }
3690
3691
3692
3693 void g_ge (unsigned flags, unsigned long val)
3694 /* Test for greater than or equal to */
3695 {
3696     static char* ops [12] = {
3697         "tosge00",      "tosgea0",      "tosgeax",
3698         "tosuge00",     "tosugea0",     "tosugeax",
3699         0,              0,              "tosgeeax",
3700         0,              0,              "tosugeeax",
3701     };
3702
3703
3704     /* If the right hand side is const, the lhs is not on stack but still
3705      * in the primary register.
3706      */
3707     if (flags & CF_CONST) {
3708
3709         /* Give a warning in some special cases */
3710         if ((flags & CF_UNSIGNED) && val == 0) {
3711             Warning ("Condition is always true");
3712         }
3713
3714         /* Look at the type */
3715         switch (flags & CF_TYPE) {
3716
3717             case CF_CHAR:
3718                 if (flags & CF_FORCECHAR) {
3719                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3720                     if (flags & CF_UNSIGNED) {
3721                         AddCodeLine ("jsr booluge");
3722                     } else {
3723                         AddCodeLine ("jsr boolge");
3724                     }
3725                     return;
3726                 }
3727                 /* FALLTHROUGH */
3728
3729             case CF_INT:
3730                 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3731                     /* If we have a signed compare against zero, we only need to
3732                      * test the high byte.
3733                      */
3734                     AddCodeLine ("txa");
3735                     AddCodeLine ("jsr boolge");
3736                     return;
3737                 }
3738                 /* Direct code only for unsigned data types */
3739                 if (flags & CF_UNSIGNED) {
3740                     unsigned L = GetLocalLabel();
3741                     AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3742                     AddCodeLine ("bne %s", LocalLabelName (L));
3743                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3744                     g_defcodelabel (L);
3745                     AddCodeLine ("jsr booluge");
3746                     return;
3747                 }
3748                 break;
3749
3750             case CF_LONG:
3751                 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3752                     /* If we have a signed compare against zero, we only need to
3753                      * test the high byte.
3754                      */
3755                     AddCodeLine ("lda sreg+1");
3756                     AddCodeLine ("jsr boolge");
3757                     return;
3758                 }
3759                 break;
3760
3761             default:
3762                 typeerror (flags);
3763         }
3764
3765         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3766          * into the normal, non-optimized stuff.
3767          */
3768         g_push (flags & ~CF_CONST, 0);
3769
3770     }
3771
3772     /* Use long way over the stack */
3773     oper (flags, val, ops);
3774 }
3775
3776
3777
3778 /*****************************************************************************/
3779 /*                         Allocating static storage                         */
3780 /*****************************************************************************/
3781
3782
3783
3784 void g_res (unsigned n)
3785 /* Reserve static storage, n bytes */
3786 {
3787     AddDataLine ("\t.res\t%u,$00", n);
3788 }
3789
3790
3791
3792 void g_defdata (unsigned flags, unsigned long val, unsigned offs)
3793 /* Define data with the size given in flags */
3794 {
3795     if (flags & CF_CONST) {
3796
3797         /* Numeric constant */
3798         switch (flags & CF_TYPE) {
3799
3800             case CF_CHAR:
3801                 AddDataLine ("\t.byte\t$%02lX", val & 0xFF);
3802                 break;
3803
3804             case CF_INT:
3805                 AddDataLine ("\t.word\t$%04lX", val & 0xFFFF);
3806                 break;
3807
3808             case CF_LONG:
3809                 AddDataLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
3810                 break;
3811
3812             default:
3813                 typeerror (flags);
3814                 break;
3815
3816         }
3817
3818     } else {
3819
3820         /* Create the correct label name */
3821         const char* Label = GetLabelName (flags, val, offs);
3822
3823         /* Labels are always 16 bit */
3824         AddDataLine ("\t.word\t%s", Label);
3825
3826     }
3827 }
3828
3829
3830
3831 void g_defbytes (const void* Bytes, unsigned Count)
3832 /* Output a row of bytes as a constant */
3833 {
3834     unsigned Chunk;
3835     char Buf [128];
3836     char* B;
3837
3838     /* Cast the buffer pointer */
3839     const unsigned char* Data = (const unsigned char*) Bytes;
3840
3841     /* Output the stuff */
3842     while (Count) {
3843
3844         /* How many go into this line? */
3845         if ((Chunk = Count) > 16) {
3846             Chunk = 16;
3847         }
3848         Count -= Chunk;
3849
3850         /* Output one line */
3851         strcpy (Buf, "\t.byte\t");
3852         B = Buf + 7;
3853         do {
3854             B += sprintf (B, "$%02X", *Data++);
3855             if (--Chunk) {
3856                 *B++ = ',';
3857             }
3858         } while (Chunk);
3859
3860         /* Output the line */
3861         AddDataLine (Buf);
3862     }
3863 }
3864
3865
3866
3867 void g_zerobytes (unsigned n)
3868 /* Output n bytes of data initialized with zero */
3869 {
3870     AddDataLine ("\t.res\t%u,$00", n);
3871 }
3872
3873
3874
3875 /*****************************************************************************/
3876 /*                       User supplied assembler code                        */
3877 /*****************************************************************************/
3878
3879
3880
3881 void g_asmcode (struct StrBuf* B)
3882 /* Output one line of assembler code. */
3883 {
3884     AddCodeLine ("%.*s", SB_GetLen (B), SB_GetConstBuf (B));
3885 }
3886
3887
3888
3889 /*****************************************************************************/
3890 /*                          Inlined known functions                          */
3891 /*****************************************************************************/
3892
3893
3894
3895 void g_strlen (unsigned flags, unsigned long val, unsigned offs)
3896 /* Inline the strlen() function */
3897 {
3898     /* We need a label in both cases */
3899     unsigned label = GetLocalLabel ();
3900
3901     /* Two different encodings */
3902     if (flags & CF_CONST) {
3903
3904         /* The address of the string is constant. Create the correct label name */
3905         char* lbuf = GetLabelName (flags, val, offs);
3906
3907         /* Generate the strlen code */
3908         AddCodeLine ("ldy #$FF");
3909         g_defcodelabel (label);
3910         AddCodeLine ("iny");
3911         AddCodeLine ("lda %s,y", lbuf);
3912         AddCodeLine ("bne %s", LocalLabelName (label));
3913         AddCodeLine ("tax");
3914         AddCodeLine ("tya");
3915
3916     } else {
3917
3918         /* Address not constant but in primary */
3919         if (CodeSizeFactor < 400) {
3920             /* This is too much code, so call strlen instead of inlining */
3921             AddCodeLine ("jsr _strlen");
3922         } else {
3923             /* Inline the function */
3924             AddCodeLine ("sta ptr1");
3925             AddCodeLine ("stx ptr1+1");
3926             AddCodeLine ("ldy #$FF");
3927             g_defcodelabel (label);
3928             AddCodeLine ("iny");
3929             AddCodeLine ("lda (ptr1),y");
3930             AddCodeLine ("bne %s", LocalLabelName (label));
3931             AddCodeLine ("tax");
3932             AddCodeLine ("tya");
3933         }
3934     }
3935 }
3936
3937
3938