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