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