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