]> git.sur5r.net Git - cc65/blob - src/cc65/codegen.c
Added code to check the 6502 stack
[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_cstackcheck (void)
2519 /* Check for a C stack overflow */
2520 {
2521     AddCodeLine ("\tjsr\tcstkchk");
2522 }
2523
2524
2525
2526 void g_stackcheck (void)
2527 /* Check for a stack overflow */
2528 {
2529     AddCodeLine ("\tjsr\tstkchk");
2530 }
2531
2532
2533
2534 void g_add (unsigned flags, unsigned long val)
2535 /* Primary = TOS + Primary */
2536 {
2537     static char* ops [12] = {
2538         0,              "tosadda0",     "tosaddax",
2539         0,              "tosadda0",     "tosaddax",
2540         0,              0,              "tosaddeax",
2541         0,              0,              "tosaddeax",
2542     };
2543
2544     if (flags & CF_CONST) {
2545         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2546         g_push (flags & ~CF_CONST, 0);
2547     }
2548     oper (flags, val, ops);
2549 }
2550
2551
2552
2553 void g_sub (unsigned flags, unsigned long val)
2554 /* Primary = TOS - Primary */
2555 {
2556     static char* ops [12] = {
2557         0,              "tossuba0",     "tossubax",
2558         0,              "tossuba0",     "tossubax",
2559         0,              0,              "tossubeax",
2560         0,              0,              "tossubeax",
2561     };
2562
2563     if (flags & CF_CONST) {
2564         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2565         g_push (flags & ~CF_CONST, 0);
2566     }
2567     oper (flags, val, ops);
2568 }
2569
2570
2571
2572 void g_rsub (unsigned flags, unsigned long val)
2573 /* Primary = Primary - TOS */
2574 {
2575     static char* ops [12] = {
2576         0,              "tosrsuba0",    "tosrsubax",
2577         0,              "tosrsuba0",    "tosrsubax",
2578         0,              0,              "tosrsubeax",
2579         0,              0,              "tosrsubeax",
2580     };
2581     oper (flags, val, ops);
2582 }
2583
2584
2585
2586 void g_mul (unsigned flags, unsigned long val)
2587 /* Primary = TOS * Primary */
2588 {
2589     static char* ops [12] = {
2590         0,              "tosmula0",     "tosmulax",
2591         0,              "tosumula0",    "tosumulax",
2592         0,              0,              "tosmuleax",
2593         0,              0,              "tosumuleax",
2594     };
2595
2596     int p2;
2597
2598     /* Do strength reduction if the value is constant and a power of two */
2599     if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2600         /* Generate a shift instead */
2601         g_asl (flags, p2);
2602         return;
2603     }
2604
2605     /* If the right hand side is const, the lhs is not on stack but still
2606      * in the primary register.
2607      */
2608     if (flags & CF_CONST) {
2609
2610         switch (flags & CF_TYPE) {
2611
2612             case CF_CHAR:
2613                 if (flags & CF_FORCECHAR) {
2614                     /* Handle some special cases */
2615                     switch (val) {
2616
2617                         case 3:
2618                             AddCodeLine ("\tsta\ttmp1");
2619                             AddCodeLine ("\tasl\ta");
2620                             AddCodeLine ("\tclc");
2621                             AddCodeLine ("\tadc\ttmp1");
2622                             return;
2623
2624                         case 5:
2625                             AddCodeLine ("\tsta\ttmp1");
2626                             AddCodeLine ("\tasl\ta");
2627                             AddCodeLine ("\tasl\ta");
2628                             AddCodeLine ("\tclc");
2629                             AddCodeLine ("\tadc\ttmp1");
2630                             return;
2631
2632                         case 10:
2633                             AddCodeLine ("\tsta\ttmp1");
2634                             AddCodeLine ("\tasl\ta");
2635                             AddCodeLine ("\tasl\ta");
2636                             AddCodeLine ("\tclc");
2637                             AddCodeLine ("\tadc\ttmp1");
2638                             AddCodeLine ("\tasl\ta");
2639                             return;
2640                     }
2641                 }
2642                 /* FALLTHROUGH */
2643
2644             case CF_INT:
2645                 break;
2646
2647             case CF_LONG:
2648                 break;
2649
2650             default:
2651                 typeerror (flags);
2652         }
2653
2654         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2655          * into the normal, non-optimized stuff.
2656          */
2657         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2658         g_push (flags & ~CF_CONST, 0);
2659
2660     }
2661
2662     /* Use long way over the stack */
2663     oper (flags, val, ops);
2664 }
2665
2666
2667
2668 void g_div (unsigned flags, unsigned long val)
2669 /* Primary = TOS / Primary */
2670 {
2671     static char* ops [12] = {
2672         0,              "tosdiva0",     "tosdivax",
2673         0,              "tosudiva0",    "tosudivax",
2674         0,              0,              "tosdiveax",
2675         0,              0,              "tosudiveax",
2676     };
2677
2678     /* Do strength reduction if the value is constant and a power of two */
2679     int p2;
2680     if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2681         /* Generate a shift instead */
2682         g_asr (flags, p2);
2683     } else {
2684         /* Generate a division */
2685         if (flags & CF_CONST) {
2686             /* lhs is not on stack */
2687             flags &= ~CF_FORCECHAR;     /* Handle chars as ints */
2688             g_push (flags & ~CF_CONST, 0);
2689         }
2690         oper (flags, val, ops);
2691     }
2692 }
2693
2694
2695
2696 void g_mod (unsigned flags, unsigned long val)
2697 /* Primary = TOS % Primary */
2698 {
2699     static char* ops [12] = {
2700         0,              "tosmoda0",     "tosmodax",
2701         0,              "tosumoda0",    "tosumodax",
2702         0,              0,              "tosmodeax",
2703         0,              0,              "tosumodeax",
2704     };
2705     int p2;
2706
2707     /* Check if we can do some cost reduction */
2708     if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2709         /* We can do that with an AND operation */
2710         g_and (flags, val - 1);
2711     } else {
2712         /* Do it the hard way... */
2713         if (flags & CF_CONST) {
2714             /* lhs is not on stack */
2715             flags &= ~CF_FORCECHAR;     /* Handle chars as ints */
2716             g_push (flags & ~CF_CONST, 0);
2717         }
2718         oper (flags, val, ops);
2719     }
2720 }
2721
2722
2723
2724 void g_or (unsigned flags, unsigned long val)
2725 /* Primary = TOS | Primary */
2726 {
2727     static char* ops [12] = {
2728         0,              "tosora0",      "tosorax",
2729         0,              "tosora0",      "tosorax",
2730         0,              0,              "tosoreax",
2731         0,              0,              "tosoreax",
2732     };
2733
2734     /* If the right hand side is const, the lhs is not on stack but still
2735      * in the primary register.
2736      */
2737     if (flags & CF_CONST) {
2738
2739         switch (flags & CF_TYPE) {
2740
2741             case CF_CHAR:
2742                 if (flags & CF_FORCECHAR) {
2743                     if ((val & 0xFF) != 0xFF) {
2744                         AddCodeLine ("\tora\t#$%02X", (unsigned char)val);
2745                     }
2746                     return;
2747                 }
2748                 /* FALLTHROUGH */
2749
2750             case CF_INT:
2751                 if (val <= 0xFF) {
2752                     AddCodeLine ("\tora\t#$%02X", (unsigned char)val);
2753                     return;
2754                 }
2755                 break;
2756
2757             case CF_LONG:
2758                 if (val <= 0xFF) {
2759                     AddCodeLine ("\tora\t#$%02X", (unsigned char)val);
2760                     return;
2761                 }
2762                 break;
2763
2764             default:
2765                 typeerror (flags);
2766         }
2767
2768         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2769          * into the normal, non-optimized stuff.
2770          */
2771         g_push (flags & ~CF_CONST, 0);
2772
2773     }
2774
2775     /* Use long way over the stack */
2776     oper (flags, val, ops);
2777 }
2778
2779
2780
2781 void g_xor (unsigned flags, unsigned long val)
2782 /* Primary = TOS ^ Primary */
2783 {
2784     static char* ops [12] = {
2785         0,              "tosxora0",     "tosxorax",
2786         0,              "tosxora0",     "tosxorax",
2787         0,              0,              "tosxoreax",
2788         0,              0,              "tosxoreax",
2789     };
2790
2791
2792     /* If the right hand side is const, the lhs is not on stack but still
2793      * in the primary register.
2794      */
2795     if (flags & CF_CONST) {
2796
2797         switch (flags & CF_TYPE) {
2798
2799             case CF_CHAR:
2800                 if (flags & CF_FORCECHAR) {
2801                     if ((val & 0xFF) != 0) {
2802                         AddCodeLine ("\teor\t#$%02X", (unsigned char)val);
2803                     }
2804                     return;
2805                 }
2806                 /* FALLTHROUGH */
2807
2808             case CF_INT:
2809                 if (val <= 0xFF) {
2810                     if (val != 0) {
2811                         AddCodeLine ("\teor\t#$%02X", (unsigned char)val);
2812                     }
2813                     return;
2814                 } else if ((val & 0xFF) == 0) {
2815                     AddCodeLine ("\tpha");
2816                     AddCodeLine ("\ttxa");
2817                     AddCodeLine ("\teor\t#$%02X", (unsigned char)(val >> 8));
2818                     AddCodeLine ("\ttax");
2819                     AddCodeLine ("\tpla");
2820                     return;
2821                 }
2822                 break;
2823
2824             case CF_LONG:
2825                 if (val <= 0xFF) {
2826                     if (val != 0) {
2827                         AddCodeLine ("\teor\t#$%02X", (unsigned char)val);
2828                     }
2829                     return;
2830                 }
2831                 break;
2832
2833             default:
2834                 typeerror (flags);
2835         }
2836
2837         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2838          * into the normal, non-optimized stuff.
2839          */
2840         g_push (flags & ~CF_CONST, 0);
2841
2842     }
2843
2844     /* Use long way over the stack */
2845     oper (flags, val, ops);
2846 }
2847
2848
2849
2850 void g_and (unsigned flags, unsigned long val)
2851 /* Primary = TOS & Primary */
2852 {
2853     static char* ops [12] = {
2854         0,              "tosanda0",     "tosandax",
2855         0,              "tosanda0",     "tosandax",
2856         0,              0,              "tosandeax",
2857         0,              0,              "tosandeax",
2858     };
2859
2860     /* If the right hand side is const, the lhs is not on stack but still
2861      * in the primary register.
2862      */
2863     if (flags & CF_CONST) {
2864
2865         switch (flags & CF_TYPE) {
2866
2867             case CF_CHAR:
2868                 if (flags & CF_FORCECHAR) {
2869                     AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
2870                     return;
2871                 }
2872                 /* FALLTHROUGH */
2873             case CF_INT:
2874                 if ((val & 0xFFFF) != 0xFFFF) {
2875                     if (val <= 0xFF) {
2876                         ldxconst (0);
2877                         if (val == 0) {
2878                             ldaconst (0);
2879                         } else if (val != 0xFF) {
2880                             AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
2881                         }
2882                     } else if ((val & 0xFF00) == 0xFF00) {
2883                         AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
2884                     } else if ((val & 0x00FF) == 0x0000) {
2885                         AddCodeLine ("\ttxa");
2886                         AddCodeLine ("\tand\t#$%02X", (unsigned char)(val >> 8));
2887                         AddCodeLine ("\ttax");
2888                         ldaconst (0);
2889                     } else {
2890                         AddCodeLine ("\ttay");
2891                         AddCodeLine ("\ttxa");
2892                         AddCodeLine ("\tand\t#$%02X", (unsigned char)(val >> 8));
2893                         AddCodeLine ("\ttax");
2894                         AddCodeLine ("\ttya");
2895                         if ((val & 0x00FF) != 0x00FF) {
2896                             AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
2897                         }
2898                     }
2899                 }
2900                 return;
2901
2902             case CF_LONG:
2903                 if (val <= 0xFF) {
2904                     ldxconst (0);
2905                     AddCodeLine ("\tstx\tsreg+1");
2906                     AddCodeLine ("\tstx\tsreg");
2907                     if ((val & 0xFF) != 0xFF) {
2908                          AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
2909                     }
2910                     return;
2911                 } else if (val == 0xFF00) {
2912                     ldaconst (0);
2913                     AddCodeLine ("\tsta\tsreg+1");
2914                     AddCodeLine ("\tsta\tsreg");
2915                     return;
2916                 }
2917                 break;
2918
2919             default:
2920                 typeerror (flags);
2921         }
2922
2923         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2924          * into the normal, non-optimized stuff.
2925          */
2926         g_push (flags & ~CF_CONST, 0);
2927
2928     }
2929
2930     /* Use long way over the stack */
2931     oper (flags, val, ops);
2932 }
2933
2934
2935
2936 void g_asr (unsigned flags, unsigned long val)
2937 /* Primary = TOS >> Primary */
2938 {
2939     static char* ops [12] = {
2940         0,              "tosasra0",     "tosasrax",
2941         0,              "tosshra0",     "tosshrax",
2942         0,              0,              "tosasreax",
2943         0,              0,              "tosshreax",
2944     };
2945
2946     /* If the right hand side is const, the lhs is not on stack but still
2947      * in the primary register.
2948      */
2949     if (flags & CF_CONST) {
2950
2951         switch (flags & CF_TYPE) {
2952
2953             case CF_CHAR:
2954             case CF_INT:
2955                 if (val >= 1 && val <= 3) {
2956                     if (flags & CF_UNSIGNED) {
2957                         AddCodeLine ("\tjsr\tshrax%ld", val);
2958                     } else {
2959                         AddCodeLine ("\tjsr\tasrax%ld", val);
2960                     }
2961                     return;
2962                 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2963                     AddCodeLine ("\ttxa");
2964                     ldxconst (0);
2965                     return;
2966                 }
2967                 break;
2968
2969             case CF_LONG:
2970                 if (val >= 1 && val <= 3) {
2971                     if (flags & CF_UNSIGNED) {
2972                         AddCodeLine ("\tjsr\tshreax%ld", val);
2973                     } else {
2974                         AddCodeLine ("\tjsr\tasreax%ld", val);
2975                     }
2976                     return;
2977                 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2978                     AddCodeLine ("\ttxa");
2979                     AddCodeLine ("\tldx\tsreg");
2980                     AddCodeLine ("\tldy\tsreg+1");
2981                     AddCodeLine ("\tsty\tsreg");
2982                     AddCodeLine ("\tldy\t#$00");
2983                     AddCodeLine ("\tsty\tsreg+1");
2984                     return;
2985                 } else if (val == 16) {
2986                     AddCodeLine ("\tldy\t#$00");
2987                     AddCodeLine ("\tldx\tsreg+1");
2988                     if ((flags & CF_UNSIGNED) == 0) {
2989                         AddCodeLine ("\tbpl\t*+3");
2990                         AddCodeLine ("\tdey");
2991                         AddCodeHint ("y:!");
2992                     }
2993                     AddCodeLine ("\tlda\tsreg");
2994                     AddCodeLine ("\tsty\tsreg+1");
2995                     AddCodeLine ("\tsty\tsreg");
2996                     return;
2997                 }
2998                 break;
2999
3000             default:
3001                 typeerror (flags);
3002         }
3003
3004         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3005          * into the normal, non-optimized stuff.
3006          */
3007         g_push (flags & ~CF_CONST, 0);
3008
3009     }
3010
3011     /* Use long way over the stack */
3012     oper (flags, val, ops);
3013 }
3014
3015
3016
3017 void g_asl (unsigned flags, unsigned long val)
3018 /* Primary = TOS << Primary */
3019 {
3020     static char* ops [12] = {
3021         0,              "tosasla0",     "tosaslax",
3022         0,              "tosshla0",     "tosshlax",
3023         0,              0,              "tosasleax",
3024         0,              0,              "tosshleax",
3025     };
3026
3027
3028     /* If the right hand side is const, the lhs is not on stack but still
3029      * in the primary register.
3030      */
3031     if (flags & CF_CONST) {
3032
3033         switch (flags & CF_TYPE) {
3034
3035             case CF_CHAR:
3036             case CF_INT:
3037                 if (val >= 1 && val <= 3) {
3038                     if (flags & CF_UNSIGNED) {
3039                         AddCodeLine ("\tjsr\tshlax%ld", val);
3040                     } else {
3041                         AddCodeLine ("\tjsr\taslax%ld", val);
3042                     }
3043                     return;
3044                 } else if (val == 8) {
3045                     AddCodeLine ("\ttax");
3046                     AddCodeLine ("\tlda\t#$00");
3047                     return;
3048                 }
3049                 break;
3050
3051             case CF_LONG:
3052                 if (val >= 1 && val <= 3) {
3053                     if (flags & CF_UNSIGNED) {
3054                         AddCodeLine ("\tjsr\tshleax%ld", val);
3055                     } else {
3056                         AddCodeLine ("\tjsr\tasleax%ld", val);
3057                     }
3058                     return;
3059                 } else if (val == 8) {
3060                     AddCodeLine ("\tldy\tsreg");
3061                     AddCodeLine ("\tsty\tsreg+1");
3062                     AddCodeLine ("\tstx\tsreg");
3063                     AddCodeLine ("\ttax");
3064                     AddCodeLine ("\tlda\t#$00");
3065                     return;
3066                 } else if (val == 16) {
3067                     AddCodeLine ("\tstx\tsreg+1");
3068                     AddCodeLine ("\tsta\tsreg");
3069                     AddCodeLine ("\tlda\t#$00");
3070                     AddCodeLine ("\ttax");
3071                     return;
3072                 }
3073                 break;
3074
3075             default:
3076                 typeerror (flags);
3077         }
3078
3079         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3080          * into the normal, non-optimized stuff.
3081          */
3082         g_push (flags & ~CF_CONST, 0);
3083
3084     }
3085
3086     /* Use long way over the stack */
3087     oper (flags, val, ops);
3088 }
3089
3090
3091
3092 void g_neg (unsigned flags)
3093 /* Primary = -Primary */
3094 {
3095     switch (flags & CF_TYPE) {
3096
3097         case CF_CHAR:
3098         case CF_INT:
3099             AddCodeLine ("\tjsr\tnegax");
3100             break;
3101
3102         case CF_LONG:
3103             AddCodeLine ("\tjsr\tnegeax");
3104             break;
3105
3106         default:
3107             typeerror (flags);
3108     }
3109 }
3110
3111
3112
3113 void g_bneg (unsigned flags)
3114 /* Primary = !Primary */
3115 {
3116     switch (flags & CF_TYPE) {
3117
3118         case CF_CHAR:
3119             AddCodeLine ("\tjsr\tbnega");
3120             break;
3121
3122         case CF_INT:
3123             AddCodeLine ("\tjsr\tbnegax");
3124             break;
3125
3126         case CF_LONG:
3127             AddCodeLine ("\tjsr\tbnegeax");
3128             break;
3129
3130         default:
3131             typeerror (flags);
3132     }
3133 }
3134
3135
3136
3137 void g_com (unsigned flags)
3138 /* Primary = ~Primary */
3139 {
3140     switch (flags & CF_TYPE) {
3141
3142         case CF_CHAR:
3143         case CF_INT:
3144             AddCodeLine ("\tjsr\tcomplax");
3145             break;
3146
3147         case CF_LONG:
3148             AddCodeLine ("\tjsr\tcompleax");
3149             break;
3150
3151         default:
3152             typeerror (flags);
3153     }
3154 }
3155
3156
3157
3158 void g_inc (unsigned flags, unsigned long val)
3159 /* Increment the primary register by a given number */
3160 {
3161     /* Don't inc by zero */
3162     if (val == 0) {
3163         return;
3164     }
3165
3166     /* Generate code for the supported types */
3167     flags &= ~CF_CONST;
3168     switch (flags & CF_TYPE) {
3169
3170         case CF_CHAR:
3171             if (flags & CF_FORCECHAR) {
3172                 if (CPU == CPU_65C02 && val <= 2) {
3173                     while (val--) {
3174                         AddCodeLine ("\tina");
3175                     }
3176                 } else {
3177                     AddCodeLine ("\tclc");
3178                     AddCodeLine ("\tadc\t#$%02X", (unsigned char)val);
3179                 }
3180                 break;
3181             }
3182             /* FALLTHROUGH */
3183
3184         case CF_INT:
3185             if (CPU == CPU_65C02 && val == 1) {
3186                 AddCodeLine ("\tina");
3187                 AddCodeLine ("\tbne\t*+3");
3188                 AddCodeLine ("\tinx");
3189                 /* Tell the optimizer that the X register may be invalid */
3190                 AddCodeHint ("x:!");
3191             } else if (FavourSize) {
3192                 /* Use jsr calls */
3193                 if (val <= 8) {
3194                     AddCodeLine ("\tjsr\tincax%lu", val);
3195                 } else if (val <= 255) {
3196                     ldyconst (val);
3197                     AddCodeLine ("\tjsr\tincaxy");
3198                 } else {
3199                     g_add (flags | CF_CONST, val);
3200                 }
3201             } else {
3202                 /* Inline the code */
3203                 if (val < 0x300) {
3204                     if ((val & 0xFF) != 0) {
3205                         AddCodeLine ("\tclc");
3206                         AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
3207                         AddCodeLine ("\tbcc\t*+3");
3208                         AddCodeLine ("\tinx");
3209                         /* Tell the optimizer that the X register may be invalid */
3210                         AddCodeHint ("x:!");
3211                     }
3212                     if (val >= 0x100) {
3213                         AddCodeLine ("\tinx");
3214                     }
3215                     if (val >= 0x200) {
3216                         AddCodeLine ("\tinx");
3217                     }
3218                 } else {
3219                     AddCodeLine ("\tclc");
3220                     if ((val & 0xFF) != 0) {
3221                         AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
3222                         /* Tell the optimizer that the X register may be invalid */
3223                         AddCodeHint ("x:!");
3224                     }
3225                     AddCodeLine ("\tpha");
3226                     AddCodeLine ("\ttxa");
3227                     AddCodeLine ("\tadc\t#$%02X", (unsigned char) (val >> 8));
3228                     AddCodeLine ("\ttax");
3229                     AddCodeLine ("\tpla");
3230                 }
3231             }
3232             break;
3233
3234         case CF_LONG:
3235             if (val <= 255) {
3236                 ldyconst (val);
3237                 AddCodeLine ("\tjsr\tinceaxy");
3238             } else {
3239                 g_add (flags | CF_CONST, val);
3240             }
3241             break;
3242
3243         default:
3244             typeerror (flags);
3245
3246     }
3247 }
3248
3249
3250
3251 void g_dec (unsigned flags, unsigned long val)
3252 /* Decrement the primary register by a given number */
3253 {
3254     /* Don't dec by zero */
3255     if (val == 0) {
3256         return;
3257     }
3258
3259     /* Generate code for the supported types */
3260     flags &= ~CF_CONST;
3261     switch (flags & CF_TYPE) {
3262
3263         case CF_CHAR:
3264             if (flags & CF_FORCECHAR) {
3265                 if (CPU == CPU_65C02 && val <= 2) {
3266                     while (val--) {
3267                         AddCodeLine ("\tdea");
3268                     }
3269                 } else {
3270                     AddCodeLine ("\tsec");
3271                     AddCodeLine ("\tsbc\t#$%02X", (unsigned char)val);
3272                 }
3273                 break;
3274             }
3275             /* FALLTHROUGH */
3276
3277         case CF_INT:
3278             if (val <= 2) {
3279                 AddCodeLine ("\tjsr\tdecax%d", (int) val);
3280             } else if (val <= 255) {
3281                 ldyconst (val);
3282                 AddCodeLine ("\tjsr\tdecaxy");
3283             } else {
3284                 g_sub (flags | CF_CONST, val);
3285             }
3286             break;
3287
3288         case CF_LONG:
3289             if (val <= 255) {
3290                 ldyconst (val);
3291                 AddCodeLine ("\tjsr\tdeceaxy");
3292             } else {
3293                 g_sub (flags | CF_CONST, val);
3294             }
3295             break;
3296
3297         default:
3298             typeerror (flags);
3299
3300     }
3301 }
3302
3303
3304
3305 /*
3306  * Following are the conditional operators. They compare the TOS against
3307  * the primary and put a literal 1 in the primary if the condition is
3308  * true, otherwise they clear the primary register
3309  */
3310
3311
3312
3313 void g_eq (unsigned flags, unsigned long val)
3314 /* Test for equal */
3315 {
3316     static char* ops [12] = {
3317         "toseq00",      "toseqa0",      "toseqax",
3318         "toseq00",      "toseqa0",      "toseqax",
3319         0,              0,              "toseqeax",
3320         0,              0,              "toseqeax",
3321     };
3322
3323     /* If the right hand side is const, the lhs is not on stack but still
3324      * in the primary register.
3325      */
3326     if (flags & CF_CONST) {
3327
3328         switch (flags & CF_TYPE) {
3329
3330             case CF_CHAR:
3331                 if (flags & CF_FORCECHAR) {
3332                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3333                     AddCodeLine ("\tjsr\tbooleq");
3334                     return;
3335                 }
3336                 /* FALLTHROUGH */
3337
3338             case CF_INT:
3339                 AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3340                 AddCodeLine ("\tbne\t*+4");
3341                 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3342                 AddCodeLine ("\tjsr\tbooleq");
3343                 return;
3344
3345             case CF_LONG:
3346                 break;
3347
3348             default:
3349                 typeerror (flags);
3350         }
3351
3352         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3353          * into the normal, non-optimized stuff.
3354          */
3355         g_push (flags & ~CF_CONST, 0);
3356
3357     }
3358
3359     /* Use long way over the stack */
3360     oper (flags, val, ops);
3361 }
3362
3363
3364
3365 void g_ne (unsigned flags, unsigned long val)
3366 /* Test for not equal */
3367 {
3368     static char* ops [12] = {
3369         "tosne00",      "tosnea0",      "tosneax",
3370         "tosne00",      "tosnea0",      "tosneax",
3371         0,              0,              "tosneeax",
3372         0,              0,              "tosneeax",
3373     };
3374
3375
3376     /* If the right hand side is const, the lhs is not on stack but still
3377      * in the primary register.
3378      */
3379     if (flags & CF_CONST) {
3380
3381         switch (flags & CF_TYPE) {
3382
3383             case CF_CHAR:
3384                 if (flags & CF_FORCECHAR) {
3385                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3386                     AddCodeLine ("\tjsr\tboolne");
3387                     return;
3388                 }
3389                 /* FALLTHROUGH */
3390
3391             case CF_INT:
3392                 AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3393                 AddCodeLine ("\tbne\t*+4");
3394                 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3395                 AddCodeLine ("\tjsr\tboolne");
3396                 return;
3397
3398             case CF_LONG:
3399                 break;
3400
3401             default:
3402                 typeerror (flags);
3403         }
3404
3405         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3406          * into the normal, non-optimized stuff.
3407          */
3408         g_push (flags & ~CF_CONST, 0);
3409
3410     }
3411
3412     /* Use long way over the stack */
3413     oper (flags, val, ops);
3414 }
3415
3416
3417
3418 void g_lt (unsigned flags, unsigned long val)
3419 /* Test for less than */
3420 {
3421     static char* ops [12] = {
3422         "toslt00",      "toslta0",      "tosltax",
3423         "tosult00",     "tosulta0",     "tosultax",
3424         0,              0,              "toslteax",
3425         0,              0,              "tosulteax",
3426     };
3427
3428     /* If the right hand side is const, the lhs is not on stack but still
3429      * in the primary register.
3430      */
3431     if (flags & CF_CONST) {
3432
3433         /* Give a warning in some special cases */
3434         if ((flags & CF_UNSIGNED) && val == 0) {
3435             Warning ("Condition is never true");
3436         }
3437
3438         /* Look at the type */
3439         switch (flags & CF_TYPE) {
3440
3441             case CF_CHAR:
3442                 if (flags & CF_FORCECHAR) {
3443                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3444                     if (flags & CF_UNSIGNED) {
3445                         AddCodeLine ("\tjsr\tboolult");
3446                     } else {
3447                         AddCodeLine ("\tjsr\tboollt");
3448                     }
3449                     return;
3450                 }
3451                 /* FALLTHROUGH */
3452
3453             case CF_INT:
3454                 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3455                     /* If we have a signed compare against zero, we only need to
3456                      * test the high byte.
3457                      */
3458                     AddCodeLine ("\ttxa");
3459                     AddCodeLine ("\tjsr\tboollt");
3460                     return;
3461                 }
3462                 /* Direct code only for unsigned data types */
3463                 if (flags & CF_UNSIGNED) {
3464                     AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3465                     AddCodeLine ("\tbne\t*+4");
3466                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3467                     AddCodeLine ("\tjsr\tboolult");
3468                     return;
3469                 }
3470                 break;
3471
3472             case CF_LONG:
3473                 break;
3474
3475             default:
3476                 typeerror (flags);
3477         }
3478
3479         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3480          * into the normal, non-optimized stuff.
3481          */
3482         g_push (flags & ~CF_CONST, 0);
3483
3484     }
3485
3486     /* Use long way over the stack */
3487     oper (flags, val, ops);
3488 }
3489
3490
3491
3492 void g_le (unsigned flags, unsigned long val)
3493 /* Test for less than or equal to */
3494 {
3495     static char* ops [12] = {
3496         "tosle00",      "toslea0",      "tosleax",
3497         "tosule00",     "tosulea0",     "tosuleax",
3498         0,              0,              "tosleeax",
3499         0,              0,              "tosuleeax",
3500     };
3501
3502
3503     /* If the right hand side is const, the lhs is not on stack but still
3504      * in the primary register.
3505      */
3506     if (flags & CF_CONST) {
3507
3508         /* Look at the type */
3509         switch (flags & CF_TYPE) {
3510
3511             case CF_CHAR:
3512                 if (flags & CF_FORCECHAR) {
3513                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3514                     if (flags & CF_UNSIGNED) {
3515                         AddCodeLine ("\tjsr\tboolule");
3516                     } else {
3517                         AddCodeLine ("\tjsr\tboolle");
3518                     }
3519                     return;
3520                 }
3521                 /* FALLTHROUGH */
3522
3523             case CF_INT:
3524                 if (flags & CF_UNSIGNED) {
3525                     AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3526                     AddCodeLine ("\tbne\t*+4");
3527                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3528                     AddCodeLine ("\tjsr\tboolule");
3529                     return;
3530                 }
3531                 break;
3532
3533             case CF_LONG:
3534                 break;
3535
3536             default:
3537                 typeerror (flags);
3538         }
3539
3540         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3541          * into the normal, non-optimized stuff.
3542          */
3543         g_push (flags & ~CF_CONST, 0);
3544
3545     }
3546
3547     /* Use long way over the stack */
3548     oper (flags, val, ops);
3549 }
3550
3551
3552
3553 void g_gt (unsigned flags, unsigned long val)
3554 /* Test for greater than */
3555 {
3556     static char* ops [12] = {
3557         "tosgt00",      "tosgta0",      "tosgtax",
3558         "tosugt00",     "tosugta0",     "tosugtax",
3559         0,              0,              "tosgteax",
3560         0,              0,              "tosugteax",
3561     };
3562
3563
3564     /* If the right hand side is const, the lhs is not on stack but still
3565      * in the primary register.
3566      */
3567     if (flags & CF_CONST) {
3568
3569         /* Look at the type */
3570         switch (flags & CF_TYPE) {
3571
3572             case CF_CHAR:
3573                 if (flags & CF_FORCECHAR) {
3574                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3575                     if (flags & CF_UNSIGNED) {
3576                         /* If we have a compare > 0, we will replace it by
3577                          * != 0 here, since both are identical but the latter
3578                          * is easier to optimize.
3579                          */
3580                         if (val & 0xFF) {
3581                             AddCodeLine ("\tjsr\tboolugt");
3582                         } else {
3583                             AddCodeLine ("\tjsr\tboolne");
3584                         }
3585                     } else {
3586                         AddCodeLine ("\tjsr\tboolgt");
3587                     }
3588                     return;
3589                 }
3590                 /* FALLTHROUGH */
3591
3592             case CF_INT:
3593                 if (flags & CF_UNSIGNED) {
3594                     /* If we have a compare > 0, we will replace it by
3595                      * != 0 here, since both are identical but the latter
3596                      * is easier to optimize.
3597                      */
3598                     if ((val & 0xFFFF) == 0) {
3599                         AddCodeLine ("\tstx\ttmp1");
3600                         AddCodeLine ("\tora\ttmp1");
3601                         AddCodeLine ("\tjsr\tboolne");
3602                     } else {
3603                         AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3604                         AddCodeLine ("\tbne\t*+4");
3605                         AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3606                         AddCodeLine ("\tjsr\tboolugt");
3607                     }
3608                     return;
3609                 }
3610                 break;
3611
3612             case CF_LONG:
3613                 break;
3614
3615             default:
3616                 typeerror (flags);
3617         }
3618
3619         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3620          * into the normal, non-optimized stuff.
3621          */
3622         g_push (flags & ~CF_CONST, 0);
3623
3624     }
3625
3626     /* Use long way over the stack */
3627     oper (flags, val, ops);
3628 }
3629
3630
3631
3632 void g_ge (unsigned flags, unsigned long val)
3633 /* Test for greater than or equal to */
3634 {
3635     static char* ops [12] = {
3636         "tosge00",      "tosgea0",      "tosgeax",
3637         "tosuge00",     "tosugea0",     "tosugeax",
3638         0,              0,              "tosgeeax",
3639         0,              0,              "tosugeeax",
3640     };
3641
3642
3643     /* If the right hand side is const, the lhs is not on stack but still
3644      * in the primary register.
3645      */
3646     if (flags & CF_CONST) {
3647
3648         /* Give a warning in some special cases */
3649         if ((flags & CF_UNSIGNED) && val == 0) {
3650             Warning ("Condition is always true");
3651         }
3652
3653         /* Look at the type */
3654         switch (flags & CF_TYPE) {
3655
3656             case CF_CHAR:
3657                 if (flags & CF_FORCECHAR) {
3658                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3659                     if (flags & CF_UNSIGNED) {
3660                         AddCodeLine ("\tjsr\tbooluge");
3661                     } else {
3662                         AddCodeLine ("\tjsr\tboolge");
3663                     }
3664                     return;
3665                 }
3666                 /* FALLTHROUGH */
3667
3668             case CF_INT:
3669                 if (flags & CF_UNSIGNED) {
3670                     AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3671                     AddCodeLine ("\tbne\t*+4");
3672                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3673                     AddCodeLine ("\tjsr\tbooluge");
3674                     return;
3675                 }
3676                 break;
3677
3678             case CF_LONG:
3679                 break;
3680
3681             default:
3682                 typeerror (flags);
3683         }
3684
3685         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3686          * into the normal, non-optimized stuff.
3687          */
3688         g_push (flags & ~CF_CONST, 0);
3689
3690     }
3691
3692     /* Use long way over the stack */
3693     oper (flags, val, ops);
3694 }
3695
3696
3697
3698 /*****************************************************************************/
3699 /*                         Allocating static storage                         */
3700 /*****************************************************************************/
3701
3702
3703
3704 void g_res (unsigned n)
3705 /* Reserve static storage, n bytes */
3706 {
3707     AddCodeLine ("\t.res\t%u,$00", n);
3708 }
3709
3710
3711
3712 void g_defdata (unsigned flags, unsigned long val, unsigned offs)
3713 /* Define data with the size given in flags */
3714 {
3715     if (flags & CF_CONST) {
3716
3717         /* Numeric constant */
3718         switch (flags & CF_TYPE) {
3719
3720             case CF_CHAR:
3721                 AddCodeLine ("\t.byte\t$%02lX", val & 0xFF);
3722                 break;
3723
3724             case CF_INT:
3725                 AddCodeLine ("\t.word\t$%04lX", val & 0xFFFF);
3726                 break;
3727
3728             case CF_LONG:
3729                 AddCodeLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
3730                 break;
3731
3732             default:
3733                 typeerror (flags);
3734                 break;
3735
3736         }
3737
3738     } else {
3739
3740         /* Create the correct label name */
3741         const char* Label = GetLabelName (flags, val, offs);
3742
3743         /* Labels are always 16 bit */
3744         AddCodeLine ("\t.word\t%s", Label);
3745
3746     }
3747 }
3748
3749
3750
3751 void g_defbytes (const unsigned char* Bytes, unsigned Count)
3752 /* Output a row of bytes as a constant */
3753 {
3754     unsigned Chunk;
3755     char Buf [128];
3756     char* B;
3757
3758     /* Output the stuff */
3759     while (Count) {
3760
3761         /* How many go into this line? */
3762         if ((Chunk = Count) > 16) {
3763             Chunk = 16;
3764         }
3765         Count -= Chunk;
3766
3767         /* Output one line */
3768         strcpy (Buf, "\t.byte\t");
3769         B = Buf + 7;
3770         do {
3771             B += sprintf (B, "$%02X", *Bytes++ & 0xFF);
3772             if (--Chunk) {
3773                 *B++ = ',';
3774             }
3775         } while (Chunk);
3776
3777         /* Output the line */
3778         AddCodeLine (Buf);
3779     }
3780 }
3781
3782
3783
3784 void g_zerobytes (unsigned n)
3785 /* Output n bytes of data initialized with zero */
3786 {
3787     AddCodeLine ("\t.res\t%u,$00", n);
3788 }
3789
3790
3791
3792 /*****************************************************************************/
3793 /*                          Inlined known functions                          */
3794 /*****************************************************************************/
3795
3796
3797
3798 void g_strlen (unsigned flags, unsigned long val, unsigned offs)
3799 /* Inline the strlen() function */
3800 {
3801     /* We need a label in both cases */
3802     unsigned label = GetLabel ();
3803
3804     /* Two different encodings */
3805     if (flags & CF_CONST) {
3806
3807         /* The address of the string is constant. Create the correct label name */
3808         char* lbuf = GetLabelName (flags, val, offs);
3809
3810         /* Generate the strlen code */
3811         AddCodeLine ("\tldy\t#$FF");
3812         g_defloclabel (label);
3813         AddCodeLine ("\tiny");
3814         AddCodeLine ("\tlda\t%s,y", lbuf);
3815         AddCodeLine ("\tbne\tL%04X", label);
3816         AddCodeLine ("\ttax");
3817         AddCodeLine ("\ttya");
3818
3819     } else {
3820
3821         /* Address not constant but in primary */
3822         if (FavourSize) {
3823             /* This is too much code, so call strlen instead of inlining */
3824             AddCodeLine ("\tjsr\t_strlen");
3825         } else {
3826             /* Inline the function */
3827             AddCodeLine ("\tsta\tptr1");
3828             AddCodeLine ("\tstx\tptr1+1");
3829             AddCodeLine ("\tldy\t#$FF");
3830             g_defloclabel (label);
3831             AddCodeLine ("\tiny");
3832             AddCodeLine ("\tlda\t(ptr1),y");
3833             AddCodeLine ("\tbne\tL%04X", label);
3834             AddCodeLine ("\ttax");
3835             AddCodeLine ("\ttya");
3836         }
3837     }
3838 }
3839
3840
3841