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