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