]> git.sur5r.net Git - cc65/blob - src/cc65/codegen.c
a24ac6b7390ac9c85dcbc5e241f17b53ab83c5c4
[cc65] / src / cc65 / codegen.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 codegen.c                                 */
4 /*                                                                           */
5 /*                            6502 code generator                            */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2001 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@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 = (segment_t) 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 = GetLocalLabel ();
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 = GetLocalLabel ();
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 && CodeSizeFactor > 140) {
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 (CodeSizeFactor > 180) {
824                     ldyconst (offs + 1);
825                     AddCodeLine ("\tlda\t(sp),y");
826                     AddCodeLine ("\ttax");
827                     AddCodeLine ("\tdey");
828                     AddCodeLine ("\tlda\t(sp),y");
829                 } else {
830                     if (offs) {
831                         ldyconst (offs+1);
832                         AddCodeLine ("\tjsr\tldaxysp");
833                     } else {
834                         AddCodeLine ("\tjsr\tldax0sp");
835                     }
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 (CodeSizeFactor > 250) {
882                         AddCodeLine ("\tsta\tptr1");
883                         AddCodeLine ("\tstx\tptr1+1");
884                         AddCodeLine ("\tldx\t#$00");
885                         AddCodeLine ("\tlda\t(ptr1,x)");
886                     } else {
887                         AddCodeLine ("\tjsr\tldaui");
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 (CodeSizeFactor < 300) {
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 void g_leavariadic (int Offs)
971 /* Fetch the address of a parameter in a variadic function into the primary
972  * register
973  */
974 {
975     unsigned ArgSizeOffs;
976
977     /* Calculate the offset relative to sp */
978     Offs -= oursp;
979
980     /* Get the offset of the parameter which is stored at sp+0 on function
981      * entry and check if this offset is reachable with a byte offset.
982      */
983     CHECK (oursp <= 0);
984     ArgSizeOffs = -oursp;
985     CheckLocalOffs (ArgSizeOffs);
986
987     /* Get the size of all parameters. */
988     if (ArgSizeOffs == 0 && CPU == CPU_65C02) {
989         AddCodeLine ("\tlda\t(sp)");
990     } else {
991         ldyconst (ArgSizeOffs);
992         AddCodeLine ("\tlda\t(sp),y");
993     }
994
995     /* Add the value of the stackpointer */
996     if (CodeSizeFactor > 250) {
997         AddCodeLine ("\tldx\tsp+1");
998         AddCodeLine ("\tclc");
999         AddCodeLine ("\tadc\tsp");
1000         AddCodeLine ("\tbcc\t*+3");
1001         AddCodeLine ("\tinx");
1002         AddCodeHint ("x:!");            /* Invalidate X */
1003     } else {
1004         AddCodeLine ("\tjsr\tleaasp");
1005     }
1006
1007     /* Add the offset to the primary */
1008     if (Offs > 0) {
1009         g_inc (CF_INT | CF_CONST, Offs);
1010     } else if (Offs < 0) {
1011         g_dec (CF_INT | CF_CONST, -Offs);
1012     }
1013 }
1014
1015
1016
1017 /*****************************************************************************/
1018 /*                             Store into memory                             */
1019 /*****************************************************************************/
1020
1021
1022
1023 void g_putstatic (unsigned flags, unsigned long label, unsigned offs)
1024 /* Store the primary register into the specified static memory cell */
1025 {
1026     /* Create the correct label name */
1027     char* lbuf = GetLabelName (flags, label, offs);
1028
1029     /* Check the size and generate the correct store operation */
1030     switch (flags & CF_TYPE) {
1031
1032         case CF_CHAR:
1033             AddCodeLine ("\tsta\t%s", lbuf);
1034             break;
1035
1036         case CF_INT:
1037             AddCodeLine ("\tsta\t%s", lbuf);
1038             AddCodeLine ("\tstx\t%s+1", lbuf);
1039             break;
1040
1041         case CF_LONG:
1042             AddCodeLine ("\tsta\t%s", lbuf);
1043             AddCodeLine ("\tstx\t%s+1", lbuf);
1044             AddCodeLine ("\tldy\tsreg");
1045             AddCodeLine ("\tsty\t%s+2", lbuf);
1046             AddCodeLine ("\tldy\tsreg+1");
1047             AddCodeLine ("\tsty\t%s+3", lbuf);
1048             break;
1049
1050         default:
1051             typeerror (flags);
1052
1053     }
1054 }
1055
1056
1057
1058 void g_putlocal (unsigned Flags, int Offs, long Val)
1059 /* Put data into local object. */
1060 {
1061     Offs -= oursp;
1062     CheckLocalOffs (Offs);
1063     switch (Flags & CF_TYPE) {
1064
1065         case CF_CHAR:
1066             if (Flags & CF_CONST) {
1067                 AddCodeLine ("\tlda\t#$%02X", (unsigned char) Val);
1068             }
1069             if (CPU == CPU_65C02 && Offs == 0) {
1070                 AddCodeLine ("\tsta\t(sp)");
1071             } else {
1072                 ldyconst (Offs);
1073                 AddCodeLine ("\tsta\t(sp),y");
1074             }
1075             break;
1076
1077         case CF_INT:
1078             if (Flags & CF_CONST) {
1079                 ldyconst (Offs+1);
1080                 AddCodeLine ("\tlda\t#$%02X", (unsigned char) (Val >> 8));
1081                 AddCodeLine ("\tsta\t(sp),y");
1082                 if ((Flags & CF_NOKEEP) == 0) {
1083                     /* Place high byte into X */
1084                     AddCodeLine ("\ttax");
1085                 }
1086                 if (CPU == CPU_65C02 && Offs == 0) {
1087                     AddCodeLine ("\tlda\t#$%02X", (unsigned char) Val);
1088                     AddCodeLine ("\tsta\t(sp)");
1089                 } else {
1090                     if ((Val & 0xFF) == Offs+1) {
1091                         /* The value we need is already in Y */
1092                         AddCodeLine ("\ttya");
1093                         AddCodeLine ("\tdey");
1094                     } else {
1095                         AddCodeLine ("\tdey");
1096                         AddCodeLine ("\tlda\t#$%02X", (unsigned char) Val);
1097                     }
1098                     AddCodeLine ("\tsta\t(sp),y");
1099                 }
1100             } else {
1101                 if ((Flags & CF_NOKEEP) == 0 || CodeSizeFactor < 160) {
1102                     if (Offs) {
1103                         ldyconst (Offs);
1104                         AddCodeLine ("\tjsr\tstaxysp");
1105                     } else {
1106                         AddCodeLine ("\tjsr\tstax0sp");
1107                     }
1108                 } else {
1109                     if (CPU == CPU_65C02 && Offs == 0) {
1110                         AddCodeLine ("\tsta\t(sp)");
1111                         ldyconst (1);
1112                         AddCodeLine ("\ttxa");
1113                         AddCodeLine ("\tsta\t(sp),y");
1114                     } else {
1115                         ldyconst (Offs);
1116                         AddCodeLine ("\tsta\t(sp),y");
1117                         AddCodeLine ("\tiny");
1118                         AddCodeLine ("\ttxa");
1119                         AddCodeLine ("\tsta\t(sp),y");
1120                     }
1121                 }
1122             }
1123             break;
1124
1125         case CF_LONG:
1126             if (Flags & CF_CONST) {
1127                 g_getimmed (Flags, Val, 0);
1128             }
1129             if (Offs) {
1130                 ldyconst (Offs);
1131                 AddCodeLine ("\tjsr\tsteaxysp");
1132             } else {
1133                 AddCodeLine ("\tjsr\tsteax0sp");
1134             }
1135             break;
1136
1137         default:
1138             typeerror (Flags);
1139
1140     }
1141 }
1142
1143
1144
1145 void g_putind (unsigned Flags, unsigned Offs)
1146 /* Store the specified object type in the primary register at the address
1147  * on the top of the stack
1148  */
1149 {
1150     /* We can handle offsets below $100 directly, larger offsets must be added
1151      * to the address. Since a/x is in use, best code is achieved by adding
1152      * just the high byte. Be sure to check if the low byte will overflow while
1153      * while storing.
1154      */
1155     if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
1156
1157         /* Overflow - we need to add the low byte also */
1158         AddCodeLine ("\tldy\t#$00");
1159         AddCodeLine ("\tclc");
1160         AddCodeLine ("\tpha");
1161         AddCodeLine ("\tlda\t#$%02X", Offs & 0xFF);
1162         AddCodeLine ("\tadc\t(sp),y");
1163         AddCodeLine ("\tsta\t(sp),y");
1164         AddCodeLine ("\tiny");
1165         AddCodeLine ("\tlda\t#$%02X", (Offs >> 8) & 0xFF);
1166         AddCodeLine ("\tadc\t(sp),y");
1167         AddCodeLine ("\tsta\t(sp),y");
1168         AddCodeLine ("\tpla");
1169
1170         /* Complete address is on stack, new offset is zero */
1171         Offs = 0;
1172
1173     } else if ((Offs & 0xFF00) != 0) {
1174
1175         /* We can just add the high byte */
1176         AddCodeLine ("\tldy\t#$01");
1177         AddCodeLine ("\tclc");
1178         AddCodeLine ("\tpha");
1179         AddCodeLine ("\tlda\t#$%02X", (Offs >> 8) & 0xFF);
1180         AddCodeLine ("\tadc\t(sp),y");
1181         AddCodeLine ("\tsta\t(sp),y");
1182         AddCodeLine ("\tpla");
1183
1184         /* Offset is now just the low byte */
1185         Offs &= 0x00FF;
1186     }
1187
1188     /* Check the size and determine operation */
1189     switch (Flags & CF_TYPE) {
1190
1191         case CF_CHAR:
1192             if (Offs) {
1193                 ldyconst (Offs);
1194                 AddCodeLine ("\tjsr\tstaspidx");
1195             } else {
1196                 AddCodeLine ("\tjsr\tstaspp");
1197             }
1198             break;
1199
1200         case CF_INT:
1201             if (Offs) {
1202                 ldyconst (Offs);
1203                 AddCodeLine ("\tjsr\tstaxspidx");
1204             } else {
1205                 AddCodeLine ("\tjsr\tstaxspp");
1206             }
1207             break;
1208
1209         case CF_LONG:
1210             if (Offs) {
1211                 ldyconst (Offs);
1212                 AddCodeLine ("\tjsr\tsteaxspidx");
1213             } else {
1214                 AddCodeLine ("\tjsr\tsteaxspp");
1215             }
1216             break;
1217
1218         default:
1219             typeerror (Flags);
1220
1221     }
1222
1223     /* Pop the argument which is always a pointer */
1224     pop (CF_PTR);
1225 }
1226
1227
1228
1229 /*****************************************************************************/
1230 /*                    type conversion and similiar stuff                     */
1231 /*****************************************************************************/
1232
1233
1234
1235 void g_toslong (unsigned flags)
1236 /* Make sure, the value on TOS is a long. Convert if necessary */
1237 {
1238     switch (flags & CF_TYPE) {
1239
1240         case CF_CHAR:
1241         case CF_INT:
1242             if (flags & CF_UNSIGNED) {
1243                 AddCodeLine ("\tjsr\ttosulong");
1244             } else {
1245                 AddCodeLine ("\tjsr\ttoslong");
1246             }
1247             push (CF_INT);
1248             break;
1249
1250         case CF_LONG:
1251             break;
1252
1253         default:
1254             typeerror (flags);
1255     }
1256 }
1257
1258
1259
1260 void g_tosint (unsigned flags)
1261 /* Make sure, the value on TOS is an int. Convert if necessary */
1262 {
1263     switch (flags & CF_TYPE) {
1264
1265         case CF_CHAR:
1266         case CF_INT:
1267             break;
1268
1269         case CF_LONG:
1270             AddCodeLine ("\tjsr\ttosint");
1271             pop (CF_INT);
1272             break;
1273
1274         default:
1275             typeerror (flags);
1276     }
1277 }
1278
1279
1280
1281 void g_reglong (unsigned flags)
1282 /* Make sure, the value in the primary register a long. Convert if necessary */
1283 {
1284     switch (flags & CF_TYPE) {
1285
1286         case CF_CHAR:
1287         case CF_INT:
1288             if (flags & CF_UNSIGNED) {
1289                 if (CodeSizeFactor >= 200) {
1290                     ldyconst (0);
1291                     AddCodeLine ("\tsty\tsreg");
1292                     AddCodeLine ("\tsty\tsreg+1");
1293                 } else {
1294                     AddCodeLine ("\tjsr\taxulong");
1295                 }
1296             } else {
1297                 AddCodeLine ("\tjsr\taxlong");
1298             }
1299             break;
1300
1301         case CF_LONG:
1302             break;
1303
1304         default:
1305             typeerror (flags);
1306     }
1307 }
1308
1309
1310
1311 unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1312 /* Adjust the integer operands before doing a binary operation. lhs is a flags
1313  * value, that corresponds to the value on TOS, rhs corresponds to the value
1314  * in (e)ax. The return value is the the flags value for the resulting type.
1315  */
1316 {
1317     unsigned ltype, rtype;
1318     unsigned result;
1319
1320     /* Get the type spec from the flags */
1321     ltype = lhs & CF_TYPE;
1322     rtype = rhs & CF_TYPE;
1323
1324     /* Check if a conversion is needed */
1325     if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1326         /* We must promote the primary register to long */
1327         g_reglong (rhs);
1328         /* Get the new rhs type */
1329         rhs = (rhs & ~CF_TYPE) | CF_LONG;
1330         rtype = CF_LONG;
1331     } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1332         /* We must promote the lhs to long */
1333         if (lhs & CF_REG) {
1334             g_reglong (lhs);
1335         } else {
1336             g_toslong (lhs);
1337         }
1338         /* Get the new rhs type */
1339         lhs = (lhs & ~CF_TYPE) | CF_LONG;
1340         ltype = CF_LONG;
1341     }
1342
1343     /* Determine the result type for the operation:
1344      *  - The result is const if both operands are const.
1345      *  - The result is unsigned if one of the operands is unsigned.
1346      *  - The result is long if one of the operands is long.
1347      *  - Otherwise the result is int sized.
1348      */
1349     result = (lhs & CF_CONST) & (rhs & CF_CONST);
1350     result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1351     if (rtype == CF_LONG || ltype == CF_LONG) {
1352         result |= CF_LONG;
1353     } else {
1354         result |= CF_INT;
1355     }
1356     return result;
1357 }
1358
1359
1360
1361 unsigned g_typecast (unsigned lhs, unsigned rhs)
1362 /* Cast the value in the primary register to the operand size that is flagged
1363  * by the lhs value. Return the result value.
1364  */
1365 {
1366     unsigned ltype, rtype;
1367
1368     /* Get the type spec from the flags */
1369     ltype = lhs & CF_TYPE;
1370     rtype = rhs & CF_TYPE;
1371
1372     /* Check if a conversion is needed */
1373     if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1374         /* We must promote the primary register to long */
1375         g_reglong (rhs);
1376     }
1377
1378     /* Do not need any other action. If the left type is int, and the primary
1379      * register is long, it will be automagically truncated. If the right hand
1380      * side is const, it is not located in the primary register and handled by
1381      * the expression parser code.
1382      */
1383
1384     /* Result is const if the right hand side was const */
1385     lhs |= (rhs & CF_CONST);
1386
1387     /* The resulting type is that of the left hand side (that's why you called
1388      * this function :-)
1389      */
1390     return lhs;
1391 }
1392
1393
1394
1395 void g_scale (unsigned flags, long val)
1396 /* Scale the value in the primary register by the given value. If val is positive,
1397  * scale up, is val is negative, scale down. This function is used to scale
1398  * the operands or results of pointer arithmetic by the size of the type, the
1399  * pointer points to.
1400  */
1401 {
1402     int p2;
1403
1404     /* Value may not be zero */
1405     if (val == 0) {
1406         Internal ("Data type has no size");
1407     } else if (val > 0) {
1408
1409         /* Scale up */
1410         if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1411
1412             /* Factor is 2, 4 or 8, use special function */
1413             switch (flags & CF_TYPE) {
1414
1415                 case CF_CHAR:
1416                     if (flags & CF_FORCECHAR) {
1417                         while (p2--) {
1418                             AddCodeLine ("\tasl\ta");
1419                         }
1420                         break;
1421                     }
1422                     /* FALLTHROUGH */
1423
1424                 case CF_INT:
1425                     if (CodeSizeFactor >= (p2+1)*130U) {
1426                         AddCodeLine ("\tstx\ttmp1");
1427                         while (p2--) {
1428                             AddCodeLine ("\tasl\ta");
1429                             AddCodeLine ("\trol\ttmp1");
1430                         }
1431                         AddCodeLine ("\tldx\ttmp1");
1432                     } else {
1433                         if (flags & CF_UNSIGNED) {
1434                             AddCodeLine ("\tjsr\tshlax%d", p2);
1435                         } else {
1436                             AddCodeLine ("\tjsr\taslax%d", p2);
1437                         }
1438                     }
1439                     break;
1440
1441                 case CF_LONG:
1442                     if (flags & CF_UNSIGNED) {
1443                         AddCodeLine ("\tjsr\tshleax%d", p2);
1444                     } else {
1445                         AddCodeLine ("\tjsr\tasleax%d", p2);
1446                     }
1447                     break;
1448
1449                 default:
1450                     typeerror (flags);
1451
1452             }
1453
1454         } else if (val != 1) {
1455
1456             /* Use a multiplication instead */
1457             g_mul (flags | CF_CONST, val);
1458
1459         }
1460
1461     } else {
1462
1463         /* Scale down */
1464         val = -val;
1465         if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1466
1467             /* Factor is 2, 4 or 8, use special function */
1468             switch (flags & CF_TYPE) {
1469
1470                 case CF_CHAR:
1471                     if (flags & CF_FORCECHAR) {
1472                         if (flags & CF_UNSIGNED) {
1473                             while (p2--) {
1474                                 AddCodeLine ("\tlsr\ta");
1475                             }
1476                             break;
1477                         } else if (p2 <= 2) {
1478                             AddCodeLine ("\tcmp\t#$80");
1479                             AddCodeLine ("\tror\ta");
1480                             break;
1481                         }
1482                     }
1483                     /* FALLTHROUGH */
1484
1485                 case CF_INT:
1486                     if (flags & CF_UNSIGNED) {
1487                         if (CodeSizeFactor >= (p2+1)*130U) {
1488                             AddCodeLine ("\tstx\ttmp1");
1489                             while (p2--) {
1490                                 AddCodeLine ("\tlsr\ttmp1");
1491                                 AddCodeLine ("\tror\ta");
1492                             }
1493                             AddCodeLine ("\tldx\ttmp1");
1494                         } else {
1495                             AddCodeLine ("\tjsr\tlsrax%d", p2);
1496                         }
1497                     } else {
1498                         if (CodeSizeFactor >= (p2+1)*150U) {
1499                             AddCodeLine ("\tstx\ttmp1");
1500                             while (p2--) {
1501                                 AddCodeLine ("\tcpx\t#$80");
1502                                 AddCodeLine ("\tror\ttmp1");
1503                                 AddCodeLine ("\tror\ta");
1504                             }
1505                             AddCodeLine ("\tldx\ttmp1");
1506                         } else {
1507                             AddCodeLine ("\tjsr\tasrax%d", p2);
1508                         }
1509                     }
1510                     break;
1511
1512                 case CF_LONG:
1513                     if (flags & CF_UNSIGNED) {
1514                         AddCodeLine ("\tjsr\tlsreax%d", p2);
1515                     } else {
1516                         AddCodeLine ("\tjsr\tasreax%d", p2);
1517                     }
1518                     break;
1519
1520                 default:
1521                     typeerror (flags);
1522
1523             }
1524
1525         } else if (val != 1) {
1526
1527             /* Use a division instead */
1528             g_div (flags | CF_CONST, val);
1529
1530         }
1531     }
1532 }
1533
1534
1535
1536 /*****************************************************************************/
1537 /*              Adds and subs of variables fix a fixed address               */
1538 /*****************************************************************************/
1539
1540
1541
1542 void g_addlocal (unsigned flags, int offs)
1543 /* Add a local variable to ax */
1544 {
1545     /* Correct the offset and check it */
1546     offs -= oursp;
1547     CheckLocalOffs (offs);
1548
1549     switch (flags & CF_TYPE) {
1550
1551         case CF_CHAR:
1552             AddCodeLine ("\tldy\t#$%02X", offs & 0xFF);
1553             AddCodeLine ("\tclc");
1554             AddCodeLine ("\tadc\t(sp),y");
1555             AddCodeLine ("\tbcc\t*+3");
1556             AddCodeLine ("\tinx");
1557             AddCodeHint ("x:!");
1558             break;
1559
1560         case CF_INT:
1561             AddCodeLine ("\tldy\t#$%02X", offs & 0xFF);
1562             AddCodeLine ("\tclc");
1563             AddCodeLine ("\tadc\t(sp),y");
1564             AddCodeLine ("\tpha");
1565             AddCodeLine ("\ttxa");
1566             AddCodeLine ("\tiny");
1567             AddCodeLine ("\tadc\t(sp),y");
1568             AddCodeLine ("\ttax");
1569             AddCodeLine ("\tpla");
1570             break;
1571
1572         case CF_LONG:
1573             /* Do it the old way */
1574             g_push (flags, 0);
1575             g_getlocal (flags, offs);
1576             g_add (flags, 0);
1577             break;
1578
1579         default:
1580             typeerror (flags);
1581
1582     }
1583 }
1584
1585
1586
1587 void g_addstatic (unsigned flags, unsigned long label, unsigned offs)
1588 /* Add a static variable to ax */
1589 {
1590     /* Create the correct label name */
1591     char* lbuf = GetLabelName (flags, label, offs);
1592
1593     switch (flags & CF_TYPE) {
1594
1595         case CF_CHAR:
1596             AddCodeLine ("\tclc");
1597             AddCodeLine ("\tadc\t%s", lbuf);
1598             AddCodeLine ("\tbcc\t*+3");
1599             AddCodeLine ("\tinx");
1600             AddCodeHint ("x:!");
1601             break;
1602
1603         case CF_INT:
1604             AddCodeLine ("\tclc");
1605             AddCodeLine ("\tadc\t%s", lbuf);
1606             AddCodeLine ("\ttay");
1607             AddCodeLine ("\ttxa");
1608             AddCodeLine ("\tadc\t%s+1", lbuf);
1609             AddCodeLine ("\ttax");
1610             AddCodeLine ("\ttya");
1611             break;
1612
1613         case CF_LONG:
1614             /* Do it the old way */
1615             g_push (flags, 0);
1616             g_getstatic (flags, label, offs);
1617             g_add (flags, 0);
1618             break;
1619
1620         default:
1621             typeerror (flags);
1622
1623     }
1624 }
1625
1626
1627
1628 /*****************************************************************************/
1629 /*             Compares of ax with a variable with fixed address             */
1630 /*****************************************************************************/
1631
1632
1633
1634 void g_cmplocal (unsigned flags, int offs)
1635 /* Compare a local variable to ax */
1636 {
1637     Internal ("g_cmplocal not implemented");
1638 }
1639
1640
1641
1642 void g_cmpstatic (unsigned flags, unsigned label, unsigned offs)
1643 /* Compare a static variable to ax */
1644 {
1645     Internal ("g_cmpstatic not implemented");
1646 }
1647
1648
1649
1650 /*****************************************************************************/
1651 /*                           Special op= functions                           */
1652 /*****************************************************************************/
1653
1654
1655
1656 void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
1657                     unsigned long val)
1658 /* Emit += for a static variable */
1659 {
1660     /* Create the correct label name */
1661     char* lbuf = GetLabelName (flags, label, offs);
1662
1663     /* Check the size and determine operation */
1664     switch (flags & CF_TYPE) {
1665
1666         case CF_CHAR:
1667             if (flags & CF_FORCECHAR) {
1668                 AddCodeLine ("\tldx\t#$00");
1669                 if (flags & CF_CONST) {
1670                     if (val == 1) {
1671                         AddCodeLine ("\tinc\t%s", lbuf);
1672                         AddCodeLine ("\tlda\t%s", lbuf);
1673                     } else {
1674                         AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1675                         AddCodeLine ("\tclc");
1676                         AddCodeLine ("\tadc\t%s", lbuf);
1677                         AddCodeLine ("\tsta\t%s", lbuf);
1678                     }
1679                 } else {
1680                     AddCodeLine ("\tclc");
1681                     AddCodeLine ("\tadc\t%s", lbuf);
1682                     AddCodeLine ("\tsta\t%s", lbuf);
1683                 }
1684                 if ((flags & CF_UNSIGNED) == 0) {
1685                     AddCodeLine ("\tbpl\t*+3");
1686                     AddCodeLine ("\tdex");
1687                     AddCodeHint ("x:!");                /* Invalidate X */
1688                 }
1689                 break;
1690             }
1691             /* FALLTHROUGH */
1692
1693         case CF_INT:
1694             if (flags & CF_CONST) {
1695                 if (val == 1) {
1696                     label = GetLocalLabel ();
1697                     AddCodeLine ("\tinc\t%s", lbuf);
1698                     AddCodeLine ("\tbne\tL%04X", (int)label);
1699                     AddCodeLine ("\tinc\t%s+1", lbuf);
1700                     g_defloclabel (label);
1701                     AddCodeLine ("\tlda\t%s", lbuf);            /* Hmmm... */
1702                     AddCodeLine ("\tldx\t%s+1", lbuf);
1703                 } else {
1704                     AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1705                     AddCodeLine ("\tclc");
1706                     AddCodeLine ("\tadc\t%s", lbuf);
1707                     AddCodeLine ("\tsta\t%s", lbuf);
1708                     if (val < 0x100) {
1709                         label = GetLocalLabel ();
1710                         AddCodeLine ("\tbcc\tL%04X", (int)label);
1711                         AddCodeLine ("\tinc\t%s+1", lbuf);
1712                         g_defloclabel (label);
1713                         AddCodeLine ("\tldx\t%s+1", lbuf);
1714                     } else {
1715                         AddCodeLine ("\tlda\t#$%02X", (unsigned char)(val >> 8));
1716                         AddCodeLine ("\tadc\t%s+1", lbuf);
1717                         AddCodeLine ("\tsta\t%s+1", lbuf);
1718                         AddCodeLine ("\ttax");
1719                         AddCodeLine ("\tlda\t%s", lbuf);
1720                     }
1721                 }
1722             } else {
1723                 AddCodeLine ("\tclc");
1724                 AddCodeLine ("\tadc\t%s", lbuf);
1725                 AddCodeLine ("\tsta\t%s", lbuf);
1726                 AddCodeLine ("\ttxa");
1727                 AddCodeLine ("\tadc\t%s+1", lbuf);
1728                 AddCodeLine ("\tsta\t%s+1", lbuf);
1729                 AddCodeLine ("\ttax");
1730                 AddCodeLine ("\tlda\t%s", lbuf);
1731             }
1732             break;
1733
1734         case CF_LONG:
1735             if (flags & CF_CONST) {
1736                 if (val < 0x100) {
1737                     AddCodeLine ("\tldy\t#<(%s)", lbuf);
1738                     AddCodeLine ("\tsty\tptr1");
1739                     AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
1740                     if (val == 1) {
1741                         AddCodeLine ("\tjsr\tladdeq1");
1742                     } else {
1743                         AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1744                         AddCodeLine ("\tjsr\tladdeqa");
1745                     }
1746                 } else {
1747                     g_getstatic (flags, label, offs);
1748                     g_inc (flags, val);
1749                     g_putstatic (flags, label, offs);
1750                 }
1751             } else {
1752                 AddCodeLine ("\tldy\t#<(%s)", lbuf);
1753                 AddCodeLine ("\tsty\tptr1");
1754                 AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
1755                 AddCodeLine ("\tjsr\tladdeq");
1756             }
1757             break;
1758
1759         default:
1760             typeerror (flags);
1761     }
1762 }
1763
1764
1765
1766 void g_addeqlocal (unsigned flags, int offs, unsigned long val)
1767 /* Emit += for a local variable */
1768 {
1769     /* Calculate the true offset, check it, load it into Y */
1770     offs -= oursp;
1771     CheckLocalOffs (offs);
1772
1773     /* Check the size and determine operation */
1774     switch (flags & CF_TYPE) {
1775
1776         case CF_CHAR:
1777             if (flags & CF_FORCECHAR) {
1778                 if (offs == 0) {
1779                     AddCodeLine ("\tldx\t#$00");
1780                     if (flags & CF_CONST) {
1781                         AddCodeLine ("\tclc");
1782                         AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1783                         AddCodeLine ("\tadc\t(sp,x)");
1784                         AddCodeLine ("\tsta\t(sp,x)");
1785                     } else {
1786                         AddCodeLine ("\tclc");
1787                         AddCodeLine ("\tadc\t(sp,x)");
1788                         AddCodeLine ("\tsta\t(sp,x)");
1789                     }
1790                 } else {
1791                     ldyconst (offs);
1792                     AddCodeLine ("\tldx\t#$00");
1793                     if (flags & CF_CONST) {
1794                         AddCodeLine ("\tclc");
1795                         AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1796                         AddCodeLine ("\tadc\t(sp),y");
1797                         AddCodeLine ("\tsta\t(sp),y");
1798                     } else {
1799                         AddCodeLine ("\tclc");
1800                         AddCodeLine ("\tadc\t(sp),y");
1801                         AddCodeLine ("\tsta\t(sp),y");
1802                     }
1803                 }
1804                 if ((flags & CF_UNSIGNED) == 0) {
1805                     AddCodeLine ("\tbpl\t*+3");
1806                     AddCodeLine ("\tdex");
1807                     AddCodeHint ("x:!");        /* Invalidate X */
1808                 }
1809                 break;
1810             }
1811             /* FALLTHROUGH */
1812
1813         case CF_INT:
1814             if (flags & CF_CONST) {
1815                 g_getimmed (flags, val, 0);
1816             }
1817             if (offs == 0) {
1818                 AddCodeLine ("\tjsr\taddeq0sp");
1819             } else {
1820                 ldyconst (offs);
1821                 AddCodeLine ("\tjsr\taddeqysp");
1822             }
1823             break;
1824
1825         case CF_LONG:
1826             if (flags & CF_CONST) {
1827                 g_getimmed (flags, val, 0);
1828             }
1829             if (offs == 0) {
1830                 AddCodeLine ("\tjsr\tladdeq0sp");
1831             } else {
1832                 ldyconst (offs);
1833                 AddCodeLine ("\tjsr\tladdeqysp");
1834             }
1835             break;
1836
1837         default:
1838             typeerror (flags);
1839     }
1840 }
1841
1842
1843
1844 void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
1845 /* Emit += for the location with address in ax */
1846 {
1847     /* If the offset is too large for a byte register, add the high byte
1848      * of the offset to the primary. Beware: We need a special correction
1849      * if the offset in the low byte will overflow in the operation.
1850      */
1851     offs = MakeByteOffs (flags, offs);
1852
1853     /* Check the size and determine operation */
1854     switch (flags & CF_TYPE) {
1855
1856         case CF_CHAR:
1857             AddCodeLine ("\tsta\tptr1");
1858             AddCodeLine ("\tstx\tptr1+1");
1859             if (offs == 0) {
1860                 AddCodeLine ("\tldx\t#$00");
1861                 AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1862                 AddCodeLine ("\tclc");
1863                 AddCodeLine ("\tadc\t(ptr1,x)");
1864                 AddCodeLine ("\tsta\t(ptr1,x)");
1865             } else {
1866                 AddCodeLine ("\tldy\t#$%02X", offs);
1867                 AddCodeLine ("\tldx\t#$00");
1868                 AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1869                 AddCodeLine ("\tclc");
1870                 AddCodeLine ("\tadc\t(ptr1),y");
1871                 AddCodeLine ("\tsta\t(ptr1),y");
1872             }
1873             break;
1874
1875         case CF_INT:
1876             if (CodeSizeFactor >= 200) {
1877                 /* Lots of code, use only if size is not important */
1878                 AddCodeLine ("\tsta\tptr1");
1879                 AddCodeLine ("\tstx\tptr1+1");
1880                 AddCodeLine ("\tldy\t#$%02X", offs);
1881                 AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1882                 AddCodeLine ("\tclc");
1883                 AddCodeLine ("\tadc\t(ptr1),y");
1884                 AddCodeLine ("\tsta\t(ptr1),y");
1885                 AddCodeLine ("\tpha");
1886                 AddCodeLine ("\tiny");
1887                 AddCodeLine ("\tlda\t#$%02X", (unsigned char)(val >> 8));
1888                 AddCodeLine ("\tadc\t(ptr1),y");
1889                 AddCodeLine ("\tsta\t(ptr1),y");
1890                 AddCodeLine ("\ttax");
1891                 AddCodeLine ("\tpla");
1892                 break;
1893             }
1894             /* FALL THROUGH */
1895
1896         case CF_LONG:
1897             AddCodeLine ("\tjsr\tpushax");      /* Push the address */
1898             push (flags);                       /* Correct the internal sp */
1899             g_getind (flags, offs);             /* Fetch the value */
1900             g_inc (flags, val);                 /* Increment value in primary */
1901             g_putind (flags, offs);             /* Store the value back */
1902             break;
1903
1904         default:
1905             typeerror (flags);
1906     }
1907 }
1908
1909
1910
1911 void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
1912                     unsigned long val)
1913 /* Emit -= for a static variable */
1914 {
1915     /* Create the correct label name */
1916     char* lbuf = GetLabelName (flags, label, offs);
1917
1918     /* Check the size and determine operation */
1919     switch (flags & CF_TYPE) {
1920
1921         case CF_CHAR:
1922             if (flags & CF_FORCECHAR) {
1923                 AddCodeLine ("\tldx\t#$00");
1924                 if (flags & CF_CONST) {
1925                     if (val == 1) {
1926                         AddCodeLine ("\tdec\t%s", lbuf);
1927                         AddCodeLine ("\tlda\t%s", lbuf);
1928                     } else {
1929                         AddCodeLine ("\tsec");
1930                         AddCodeLine ("\tlda\t%s", lbuf);
1931                         AddCodeLine ("\tsbc\t#$%02X", (int)(val & 0xFF));
1932                         AddCodeLine ("\tsta\t%s", lbuf);
1933                     }
1934                 } else {
1935                     AddCodeLine ("\tsec");
1936                     AddCodeLine ("\tsta\ttmp1");
1937                     AddCodeLine ("\tlda\t%s", lbuf);
1938                     AddCodeLine ("\tsbc\ttmp1");
1939                     AddCodeLine ("\tsta\t%s", lbuf);
1940                 }
1941                 if ((flags & CF_UNSIGNED) == 0) {
1942                     AddCodeLine ("\tbpl\t*+3");
1943                     AddCodeLine ("\tdex");
1944                     AddCodeHint ("x:!");                /* Invalidate X */
1945                 }
1946                 break;
1947             }
1948             /* FALLTHROUGH */
1949
1950         case CF_INT:
1951             AddCodeLine ("\tsec");
1952             if (flags & CF_CONST) {
1953                 AddCodeLine ("\tlda\t%s", lbuf);
1954                 AddCodeLine ("\tsbc\t#$%02X", (unsigned char)val);
1955                 AddCodeLine ("\tsta\t%s", lbuf);
1956                 if (val < 0x100) {
1957                     label = GetLocalLabel ();
1958                     AddCodeLine ("\tbcs\tL%04X", (unsigned)label);
1959                     AddCodeLine ("\tdec\t%s+1", lbuf);
1960                     g_defloclabel (label);
1961                     AddCodeLine ("\tldx\t%s+1", lbuf);
1962                 } else {
1963                     AddCodeLine ("\tlda\t%s+1", lbuf);
1964                     AddCodeLine ("\tsbc\t#$%02X", (unsigned char)(val >> 8));
1965                     AddCodeLine ("\tsta\t%s+1", lbuf);
1966                     AddCodeLine ("\ttax");
1967                     AddCodeLine ("\tlda\t%s", lbuf);
1968                 }
1969             } else {
1970                 AddCodeLine ("\tsta\ttmp1");
1971                 AddCodeLine ("\tlda\t%s", lbuf);
1972                 AddCodeLine ("\tsbc\ttmp1");
1973                 AddCodeLine ("\tsta\t%s", lbuf);
1974                 AddCodeLine ("\tstx\ttmp1");
1975                 AddCodeLine ("\tlda\t%s+1", lbuf);
1976                 AddCodeLine ("\tsbc\ttmp1");
1977                 AddCodeLine ("\tsta\t%s+1", lbuf);
1978                 AddCodeLine ("\ttax");
1979                 AddCodeLine ("\tlda\t%s", lbuf);
1980             }
1981             break;
1982
1983         case CF_LONG:
1984             if (flags & CF_CONST) {
1985                 if (val < 0x100) {
1986                     AddCodeLine ("\tldy\t#<(%s)", lbuf);
1987                     AddCodeLine ("\tsty\tptr1");
1988                     AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
1989                     if (val == 1) {
1990                         AddCodeLine ("\tjsr\tlsubeq1");
1991                     } else {
1992                         AddCodeLine ("\tlda\t#$%02X", (unsigned char)val);
1993                         AddCodeLine ("\tjsr\tlsubeqa");
1994                     }
1995                 } else {
1996                     g_getstatic (flags, label, offs);
1997                     g_dec (flags, val);
1998                     g_putstatic (flags, label, offs);
1999                 }
2000             } else {
2001                 AddCodeLine ("\tldy\t#<(%s)", lbuf);
2002                 AddCodeLine ("\tsty\tptr1");
2003                 AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
2004                 AddCodeLine ("\tjsr\tlsubeq");
2005             }
2006             break;
2007
2008         default:
2009             typeerror (flags);
2010     }
2011 }
2012
2013
2014
2015 void g_subeqlocal (unsigned flags, int offs, unsigned long val)
2016 /* Emit -= for a local variable */
2017 {
2018     /* Calculate the true offset, check it, load it into Y */
2019     offs -= oursp;
2020     CheckLocalOffs (offs);
2021
2022     /* Check the size and determine operation */
2023     switch (flags & CF_TYPE) {
2024
2025         case CF_CHAR:
2026             if (flags & CF_FORCECHAR) {
2027                 ldyconst (offs);
2028                 AddCodeLine ("\tldx\t#$00");
2029                 AddCodeLine ("\tsec");
2030                 if (flags & CF_CONST) {
2031                     AddCodeLine ("\tlda\t(sp),y");
2032                     AddCodeLine ("\tsbc\t#$%02X", (unsigned char)val);
2033                 } else {
2034                     AddCodeLine ("\tsta\ttmp1");
2035                     AddCodeLine ("\tlda\t(sp),y");
2036                     AddCodeLine ("\tsbc\ttmp1");
2037                 }
2038                 AddCodeLine ("\tsta\t(sp),y");
2039                 if ((flags & CF_UNSIGNED) == 0) {
2040                     AddCodeLine ("\tbpl\t*+3");
2041                     AddCodeLine ("\tdex");
2042                     AddCodeHint ("x:!");                /* Invalidate X */
2043                 }
2044                 break;
2045             }
2046             /* FALLTHROUGH */
2047
2048         case CF_INT:
2049             if (flags & CF_CONST) {
2050                 g_getimmed (flags, val, 0);
2051             }
2052             if (offs == 0) {
2053                 AddCodeLine ("\tjsr\tsubeq0sp");
2054             } else {
2055                 ldyconst (offs);
2056                 AddCodeLine ("\tjsr\tsubeqysp");
2057             }
2058             break;
2059
2060         case CF_LONG:
2061             if (flags & CF_CONST) {
2062                 g_getimmed (flags, val, 0);
2063             }
2064             if (offs == 0) {
2065                 AddCodeLine ("\tjsr\tlsubeq0sp");
2066             } else {
2067                 ldyconst (offs);
2068                 AddCodeLine ("\tjsr\tlsubeqysp");
2069             }
2070             break;
2071
2072         default:
2073             typeerror (flags);
2074     }
2075 }
2076
2077
2078
2079 void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
2080 /* Emit -= for the location with address in ax */
2081 {
2082     /* If the offset is too large for a byte register, add the high byte
2083      * of the offset to the primary. Beware: We need a special correction
2084      * if the offset in the low byte will overflow in the operation.
2085      */
2086     offs = MakeByteOffs (flags, offs);
2087
2088     /* Check the size and determine operation */
2089     switch (flags & CF_TYPE) {
2090
2091         case CF_CHAR:
2092             AddCodeLine ("\tsta\tptr1");
2093             AddCodeLine ("\tstx\tptr1+1");
2094             if (offs == 0) {
2095                 AddCodeLine ("\tldx\t#$00");
2096                 AddCodeLine ("\tlda\t(ptr1,x)");
2097                 AddCodeLine ("\tsec");
2098                 AddCodeLine ("\tsbc\t#$%02X", (unsigned char)val);
2099                 AddCodeLine ("\tsta\t(ptr1,x)");
2100             } else {
2101                 AddCodeLine ("\tldy\t#$%02X", offs);
2102                 AddCodeLine ("\tldx\t#$00");
2103                 AddCodeLine ("\tlda\t(ptr1),y");
2104                 AddCodeLine ("\tsec");
2105                 AddCodeLine ("\tsbc\t#$%02X", (unsigned char)val);
2106                 AddCodeLine ("\tsta\t(ptr1),y");
2107             }
2108             break;
2109
2110         case CF_INT:
2111             if (CodeSizeFactor >= 200) {
2112                 /* Lots of code, use only if size is not important */
2113                 AddCodeLine ("\tsta\tptr1");
2114                 AddCodeLine ("\tstx\tptr1+1");
2115                 AddCodeLine ("\tldy\t#$%02X", offs);
2116                 AddCodeLine ("\tlda\t(ptr1),y");
2117                 AddCodeLine ("\tsec");
2118                 AddCodeLine ("\tsbc\t#$%02X", (unsigned char)val);
2119                 AddCodeLine ("\tsta\t(ptr1),y");
2120                 AddCodeLine ("\tpha");
2121                 AddCodeLine ("\tiny");
2122                 AddCodeLine ("\tlda\t(ptr1),y");
2123                 AddCodeLine ("\tsbc\t#$%02X", (unsigned char)(val >> 8));
2124                 AddCodeLine ("\tsta\t(ptr1),y");
2125                 AddCodeLine ("\ttax");
2126                 AddCodeLine ("\tpla");
2127                 break;
2128             }
2129             /* FALL THROUGH */
2130
2131         case CF_LONG:
2132             AddCodeLine ("\tjsr\tpushax");      /* Push the address */
2133             push (flags);                       /* Correct the internal sp */
2134             g_getind (flags, offs);             /* Fetch the value */
2135             g_dec (flags, val);                 /* Increment value in primary */
2136             g_putind (flags, offs);             /* Store the value back */
2137             break;
2138
2139         default:
2140             typeerror (flags);
2141     }
2142 }
2143
2144
2145
2146 /*****************************************************************************/
2147 /*                 Add a variable address to the value in ax                 */
2148 /*****************************************************************************/
2149
2150
2151
2152 void g_addaddr_local (unsigned flags, int offs)
2153 /* Add the address of a local variable to ax */
2154 {
2155     /* Add the offset */
2156     offs -= oursp;
2157     if (offs != 0) {
2158         /* We cannot address more then 256 bytes of locals anyway */
2159         CheckLocalOffs (offs);
2160         AddCodeLine ("\tclc");
2161         AddCodeLine ("\tadc\t#$%02X", offs & 0xFF);
2162         AddCodeLine ("\tbcc\t*+4");     /* Do also skip the CLC insn below */
2163         AddCodeLine ("\tinx");
2164         AddCodeHint ("x:!");                    /* Invalidate X */
2165     }
2166
2167     /* Add the current stackpointer value */
2168     AddCodeLine ("\tclc");
2169     AddCodeLine ("\tadc\tsp");
2170     AddCodeLine ("\ttay");
2171     AddCodeLine ("\ttxa");
2172     AddCodeLine ("\tadc\tsp+1");
2173     AddCodeLine ("\ttax");
2174     AddCodeLine ("\ttya");
2175 }
2176
2177
2178
2179 void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs)
2180 /* Add the address of a static variable to ax */
2181 {
2182     /* Create the correct label name */
2183     char* lbuf = GetLabelName (flags, label, offs);
2184
2185     /* Add the address to the current ax value */
2186     AddCodeLine ("\tclc");
2187     AddCodeLine ("\tadc\t#<(%s)", lbuf);
2188     AddCodeLine ("\ttay");
2189     AddCodeLine ("\ttxa");
2190     AddCodeLine ("\tadc\t#>(%s)", lbuf);
2191     AddCodeLine ("\ttax");
2192     AddCodeLine ("\ttya");
2193 }
2194
2195
2196
2197 /*****************************************************************************/
2198 /*                                                                           */
2199 /*****************************************************************************/
2200
2201
2202
2203 void g_save (unsigned flags)
2204 /* Copy primary register to hold register. */
2205 {
2206     /* Check the size and determine operation */
2207     switch (flags & CF_TYPE) {
2208
2209         case CF_CHAR:
2210             if (flags & CF_FORCECHAR) {
2211                 AddCodeLine ("\tpha");
2212                 break;
2213             }
2214             /* FALLTHROUGH */
2215
2216         case CF_INT:
2217             AddCodeLine ("\tsta\tregsave");
2218             AddCodeLine ("\tstx\tregsave+1");
2219             break;
2220
2221         case CF_LONG:
2222             AddCodeLine ("\tjsr\tsaveeax");
2223             break;
2224
2225         default:
2226             typeerror (flags);
2227     }
2228 }
2229
2230
2231
2232 void g_restore (unsigned flags)
2233 /* Copy hold register to P. */
2234 {
2235     /* Check the size and determine operation */
2236     switch (flags & CF_TYPE) {
2237
2238         case CF_CHAR:
2239             if (flags & CF_FORCECHAR) {
2240                 AddCodeLine ("\tpla");
2241                 break;
2242             }
2243             /* FALLTHROUGH */
2244
2245         case CF_INT:
2246             AddCodeLine ("\tlda\tregsave");
2247             AddCodeLine ("\tldx\tregsave+1");
2248             break;
2249
2250         case CF_LONG:
2251             AddCodeLine ("\tjsr\tresteax");
2252             break;
2253
2254         default:
2255             typeerror (flags);
2256     }
2257 }
2258
2259
2260
2261 void g_cmp (unsigned flags, unsigned long val)
2262 /* Immidiate compare. The primary register will not be changed, Z flag
2263  * will be set.
2264  */
2265 {
2266     /* Check the size and determine operation */
2267     switch (flags & CF_TYPE) {
2268
2269         case CF_CHAR:
2270             if (flags & CF_FORCECHAR) {
2271                 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
2272                 break;
2273             }
2274             /* FALLTHROUGH */
2275
2276         case CF_INT:
2277             AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
2278             AddCodeLine ("\tbne\t*+4");
2279             AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
2280             break;
2281
2282         case CF_LONG:
2283             Internal ("g_cmp: Long compares not implemented");
2284             break;
2285
2286         default:
2287             typeerror (flags);
2288     }
2289 }
2290
2291
2292
2293 static void oper (unsigned flags, unsigned long val, char** subs)
2294 /* Encode a binary operation. subs is a pointer to four groups of three
2295  * strings:
2296  *      0-2     --> Operate on ints
2297  *      3-5     --> Operate on unsigneds
2298  *      6-8     --> Operate on longs
2299  *      9-11    --> Operate on unsigned longs
2300  *
2301  * The first subroutine names in each string group is used to encode an
2302  * operation with a zero constant, the second to encode an operation with
2303  * a 8 bit constant, and the third is used in all other cases.
2304  */
2305 {
2306     unsigned offs;
2307
2308     /* Determine the offset into the array */
2309     offs = (flags & CF_UNSIGNED)? 3 : 0;
2310     switch (flags & CF_TYPE) {
2311         case CF_CHAR:
2312         case CF_INT:
2313             break;
2314
2315         case CF_LONG:
2316             offs += 6;
2317             break;
2318
2319         default:
2320             typeerror (flags);
2321     }
2322
2323     /* Encode the operation */
2324     if (flags & CF_CONST) {
2325         /* Constant value given */
2326         if (val == 0 && subs [offs+0]) {
2327             /* Special case: constant with value zero */
2328             AddCodeLine ("\tjsr\t%s", subs [offs+0]);
2329         } else if (val < 0x100 && subs [offs+1]) {
2330             /* Special case: constant with high byte zero */
2331             ldaconst (val);             /* Load low byte */
2332             AddCodeLine ("\tjsr\t%s", subs [offs+1]);
2333         } else {
2334             /* Others: arbitrary constant value */
2335             g_getimmed (flags, val, 0);                 /* Load value */
2336             AddCodeLine ("\tjsr\t%s", subs [offs+2]);
2337         }
2338     } else {
2339         /* Value not constant (is already in (e)ax) */
2340         AddCodeLine ("\tjsr\t%s", subs [offs+2]);
2341     }
2342
2343     /* The operation will pop it's argument */
2344     pop (flags);
2345 }
2346
2347
2348
2349 void g_test (unsigned flags)
2350 /* Force a test to set cond codes right */
2351 {
2352     switch (flags & CF_TYPE) {
2353
2354         case CF_CHAR:
2355             if (flags & CF_FORCECHAR) {
2356                 AddCodeLine ("\ttax");
2357                 break;
2358             }
2359             /* FALLTHROUGH */
2360
2361         case CF_INT:
2362             AddCodeLine ("\tstx\ttmp1");
2363             AddCodeLine ("\tora\ttmp1");
2364             break;
2365
2366         case CF_LONG:
2367             if (flags & CF_UNSIGNED) {
2368                 AddCodeLine ("\tjsr\tutsteax");
2369             } else {
2370                 AddCodeLine ("\tjsr\ttsteax");
2371             }
2372             break;
2373
2374         default:
2375             typeerror (flags);
2376
2377     }
2378 }
2379
2380
2381
2382 void g_push (unsigned flags, unsigned long val)
2383 /* Push the primary register or a constant value onto the stack */
2384 {
2385     unsigned char hi;
2386
2387     if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
2388
2389         /* We have a constant 8 or 16 bit value */
2390         if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
2391
2392             /* Handle as 8 bit value */
2393             if (CodeSizeFactor >= 165 || val > 2) {
2394                 ldaconst (val);
2395                 AddCodeLine ("\tjsr\tpusha");
2396             } else {
2397                 AddCodeLine ("\tjsr\tpushc%d", (int) val);
2398             }
2399
2400         } else {
2401
2402             /* Handle as 16 bit value */
2403             hi = (unsigned char) (val >> 8);
2404             if (val <= 7) {
2405                 AddCodeLine ("\tjsr\tpush%u", (unsigned) val);
2406             } else if (hi == 0 || hi == 0xFF) {
2407                 /* Use special function */
2408                 ldaconst (val);
2409                 AddCodeLine ("\tjsr\t%s", (hi == 0)? "pusha0" : "pushaFF");
2410             } else {
2411                 /* Long way ... */
2412                 g_getimmed (flags, val, 0);
2413                 AddCodeLine ("\tjsr\tpushax");
2414             }
2415         }
2416
2417     } else {
2418
2419         /* Value is not 16 bit or not constant */
2420         if (flags & CF_CONST) {
2421             /* Constant 32 bit value, load into eax */
2422             g_getimmed (flags, val, 0);
2423         }
2424
2425         /* Push the primary register */
2426         switch (flags & CF_TYPE) {
2427
2428             case CF_CHAR:
2429                 if (flags & CF_FORCECHAR) {
2430                     /* Handle as char */
2431                     AddCodeLine ("\tjsr\tpusha");
2432                     break;
2433                 }
2434                 /* FALL THROUGH */
2435             case CF_INT:
2436                 AddCodeLine ("\tjsr\tpushax");
2437                 break;
2438
2439             case CF_LONG:
2440                 AddCodeLine ("\tjsr\tpusheax");
2441                 break;
2442
2443             default:
2444                 typeerror (flags);
2445
2446         }
2447
2448     }
2449
2450     /* Adjust the stack offset */
2451     push (flags);
2452 }
2453
2454
2455
2456 void g_swap (unsigned flags)
2457 /* Swap the primary register and the top of the stack. flags give the type
2458  * of *both* values (must have same size).
2459  */
2460 {
2461     switch (flags & CF_TYPE) {
2462
2463         case CF_CHAR:
2464         case CF_INT:
2465             AddCodeLine ("\tjsr\tswapstk");
2466             break;
2467
2468         case CF_LONG:
2469             AddCodeLine ("\tjsr\tswapestk");
2470             break;
2471
2472         default:
2473             typeerror (flags);
2474
2475     }
2476 }
2477
2478
2479
2480 void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
2481 /* Call the specified subroutine name */
2482 {
2483     if ((Flags & CF_FIXARGC) == 0) {
2484         /* Pass the argument count */
2485         ldyconst (ArgSize);
2486     }
2487     AddCodeLine ("\tjsr\t_%s", Label);
2488     oursp += ArgSize;           /* callee pops args */
2489 }
2490
2491
2492
2493 void g_callind (unsigned Flags, unsigned ArgSize)
2494 /* Call subroutine with address in AX */
2495 {
2496     if ((Flags & CF_FIXARGC) == 0) {
2497         /* Pass arg count */
2498         ldyconst (ArgSize);
2499     }
2500     AddCodeLine ("\tjsr\tcallax");      /* do the call */
2501     oursp += ArgSize;                   /* callee pops args */
2502 }
2503
2504
2505
2506 void g_jump (unsigned Label)
2507 /* Jump to specified internal label number */
2508 {
2509     AddCodeLine ("\tjmp\tL%04X", Label);
2510 }
2511
2512
2513
2514 void g_switch (unsigned Flags)
2515 /* Output switch statement preamble */
2516 {
2517     switch (Flags & CF_TYPE) {
2518
2519         case CF_CHAR:
2520         case CF_INT:
2521             AddCodeLine ("\tjsr\tswitch");
2522             break;
2523
2524         case CF_LONG:
2525             AddCodeLine ("\tjsr\tlswitch");
2526             break;
2527
2528         default:
2529             typeerror (Flags);
2530
2531     }
2532 }
2533
2534
2535
2536 void g_case (unsigned flags, unsigned label, unsigned long val)
2537 /* Create table code for one case selector */
2538 {
2539     switch (flags & CF_TYPE) {
2540
2541         case CF_CHAR:
2542         case CF_INT:
2543             AddCodeLine ("\t.word\t$%04X, L%04X",
2544                          (unsigned)(val & 0xFFFF),
2545                          (unsigned)(label & 0xFFFF));
2546             break;
2547
2548         case CF_LONG:
2549             AddCodeLine ("\t.dword\t$%08lX", val);
2550             AddCodeLine ("\t.word\tL%04X", label & 0xFFFF);
2551             break;
2552
2553         default:
2554             typeerror (flags);
2555
2556     }
2557 }
2558
2559
2560
2561 void g_truejump (unsigned flags, unsigned label)
2562 /* Jump to label if zero flag clear */
2563 {
2564     if (flags & CF_SHORT) {
2565         AddCodeLine ("\tbne\tL%04X", label);
2566     } else {
2567         AddCodeLine ("\tjne\tL%04X", label);
2568     }
2569 }
2570
2571
2572
2573 void g_falsejump (unsigned flags, unsigned label)
2574 /* Jump to label if zero flag set */
2575 {
2576     if (flags & CF_SHORT) {
2577         AddCodeLine ("\tbeq\tL%04X", label);
2578     } else {
2579         AddCodeLine ("\tjeq\tL%04X", label);
2580     }
2581 }
2582
2583
2584
2585 static void mod_internal (int k, char* verb1, char* verb2)
2586 {
2587     if (k <= 8) {
2588         AddCodeLine ("\tjsr\t%ssp%c", verb1, k + '0');
2589     } else {
2590         CheckLocalOffs (k);
2591         ldyconst (k);
2592         AddCodeLine ("\tjsr\t%ssp", verb2);
2593     }
2594 }
2595
2596
2597
2598 void g_space (int space)
2599 /* Create or drop space on the stack */
2600 {
2601     if (space < 0) {
2602         mod_internal (-space, "inc", "addy");
2603     } else if (space > 0) {
2604         mod_internal (space, "dec", "suby");
2605     }
2606 }
2607
2608
2609
2610 void g_cstackcheck (void)
2611 /* Check for a C stack overflow */
2612 {
2613     AddCodeLine ("\tjsr\tcstkchk");
2614 }
2615
2616
2617
2618 void g_stackcheck (void)
2619 /* Check for a stack overflow */
2620 {
2621     AddCodeLine ("\tjsr\tstkchk");
2622 }
2623
2624
2625
2626 void g_add (unsigned flags, unsigned long val)
2627 /* Primary = TOS + Primary */
2628 {
2629     static char* ops [12] = {
2630         0,              "tosadda0",     "tosaddax",
2631         0,              "tosadda0",     "tosaddax",
2632         0,              0,              "tosaddeax",
2633         0,              0,              "tosaddeax",
2634     };
2635
2636     if (flags & CF_CONST) {
2637         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2638         g_push (flags & ~CF_CONST, 0);
2639     }
2640     oper (flags, val, ops);
2641 }
2642
2643
2644
2645 void g_sub (unsigned flags, unsigned long val)
2646 /* Primary = TOS - Primary */
2647 {
2648     static char* ops [12] = {
2649         0,              "tossuba0",     "tossubax",
2650         0,              "tossuba0",     "tossubax",
2651         0,              0,              "tossubeax",
2652         0,              0,              "tossubeax",
2653     };
2654
2655     if (flags & CF_CONST) {
2656         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2657         g_push (flags & ~CF_CONST, 0);
2658     }
2659     oper (flags, val, ops);
2660 }
2661
2662
2663
2664 void g_rsub (unsigned flags, unsigned long val)
2665 /* Primary = Primary - TOS */
2666 {
2667     static char* ops [12] = {
2668         0,              "tosrsuba0",    "tosrsubax",
2669         0,              "tosrsuba0",    "tosrsubax",
2670         0,              0,              "tosrsubeax",
2671         0,              0,              "tosrsubeax",
2672     };
2673     oper (flags, val, ops);
2674 }
2675
2676
2677
2678 void g_mul (unsigned flags, unsigned long val)
2679 /* Primary = TOS * Primary */
2680 {
2681     static char* ops [12] = {
2682         0,              "tosmula0",     "tosmulax",
2683         0,              "tosumula0",    "tosumulax",
2684         0,              0,              "tosmuleax",
2685         0,              0,              "tosumuleax",
2686     };
2687
2688     int p2;
2689
2690     /* Do strength reduction if the value is constant and a power of two */
2691     if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2692         /* Generate a shift instead */
2693         g_asl (flags, p2);
2694         return;
2695     }
2696
2697     /* If the right hand side is const, the lhs is not on stack but still
2698      * in the primary register.
2699      */
2700     if (flags & CF_CONST) {
2701
2702         switch (flags & CF_TYPE) {
2703
2704             case CF_CHAR:
2705                 if (flags & CF_FORCECHAR) {
2706                     /* Handle some special cases */
2707                     switch (val) {
2708
2709                         case 3:
2710                             AddCodeLine ("\tsta\ttmp1");
2711                             AddCodeLine ("\tasl\ta");
2712                             AddCodeLine ("\tclc");
2713                             AddCodeLine ("\tadc\ttmp1");
2714                             return;
2715
2716                         case 5:
2717                             AddCodeLine ("\tsta\ttmp1");
2718                             AddCodeLine ("\tasl\ta");
2719                             AddCodeLine ("\tasl\ta");
2720                             AddCodeLine ("\tclc");
2721                             AddCodeLine ("\tadc\ttmp1");
2722                             return;
2723
2724                         case 10:
2725                             AddCodeLine ("\tsta\ttmp1");
2726                             AddCodeLine ("\tasl\ta");
2727                             AddCodeLine ("\tasl\ta");
2728                             AddCodeLine ("\tclc");
2729                             AddCodeLine ("\tadc\ttmp1");
2730                             AddCodeLine ("\tasl\ta");
2731                             return;
2732                     }
2733                 }
2734                 /* FALLTHROUGH */
2735
2736             case CF_INT:
2737                 break;
2738
2739             case CF_LONG:
2740                 break;
2741
2742             default:
2743                 typeerror (flags);
2744         }
2745
2746         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2747          * into the normal, non-optimized stuff.
2748          */
2749         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2750         g_push (flags & ~CF_CONST, 0);
2751
2752     }
2753
2754     /* Use long way over the stack */
2755     oper (flags, val, ops);
2756 }
2757
2758
2759
2760 void g_div (unsigned flags, unsigned long val)
2761 /* Primary = TOS / Primary */
2762 {
2763     static char* ops [12] = {
2764         0,              "tosdiva0",     "tosdivax",
2765         0,              "tosudiva0",    "tosudivax",
2766         0,              0,              "tosdiveax",
2767         0,              0,              "tosudiveax",
2768     };
2769
2770     /* Do strength reduction if the value is constant and a power of two */
2771     int p2;
2772     if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2773         /* Generate a shift instead */
2774         g_asr (flags, p2);
2775     } else {
2776         /* Generate a division */
2777         if (flags & CF_CONST) {
2778             /* lhs is not on stack */
2779             flags &= ~CF_FORCECHAR;     /* Handle chars as ints */
2780             g_push (flags & ~CF_CONST, 0);
2781         }
2782         oper (flags, val, ops);
2783     }
2784 }
2785
2786
2787
2788 void g_mod (unsigned flags, unsigned long val)
2789 /* Primary = TOS % Primary */
2790 {
2791     static char* ops [12] = {
2792         0,              "tosmoda0",     "tosmodax",
2793         0,              "tosumoda0",    "tosumodax",
2794         0,              0,              "tosmodeax",
2795         0,              0,              "tosumodeax",
2796     };
2797     int p2;
2798
2799     /* Check if we can do some cost reduction */
2800     if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2801         /* We can do that with an AND operation */
2802         g_and (flags, val - 1);
2803     } else {
2804         /* Do it the hard way... */
2805         if (flags & CF_CONST) {
2806             /* lhs is not on stack */
2807             flags &= ~CF_FORCECHAR;     /* Handle chars as ints */
2808             g_push (flags & ~CF_CONST, 0);
2809         }
2810         oper (flags, val, ops);
2811     }
2812 }
2813
2814
2815
2816 void g_or (unsigned flags, unsigned long val)
2817 /* Primary = TOS | Primary */
2818 {
2819     static char* ops [12] = {
2820         0,              "tosora0",      "tosorax",
2821         0,              "tosora0",      "tosorax",
2822         0,              0,              "tosoreax",
2823         0,              0,              "tosoreax",
2824     };
2825
2826     /* If the right hand side is const, the lhs is not on stack but still
2827      * in the primary register.
2828      */
2829     if (flags & CF_CONST) {
2830
2831         switch (flags & CF_TYPE) {
2832
2833             case CF_CHAR:
2834                 if (flags & CF_FORCECHAR) {
2835                     if ((val & 0xFF) != 0xFF) {
2836                         AddCodeLine ("\tora\t#$%02X", (unsigned char)val);
2837                     }
2838                     return;
2839                 }
2840                 /* FALLTHROUGH */
2841
2842             case CF_INT:
2843                 if (val <= 0xFF) {
2844                     AddCodeLine ("\tora\t#$%02X", (unsigned char)val);
2845                     return;
2846                 }
2847                 break;
2848
2849             case CF_LONG:
2850                 if (val <= 0xFF) {
2851                     AddCodeLine ("\tora\t#$%02X", (unsigned char)val);
2852                     return;
2853                 }
2854                 break;
2855
2856             default:
2857                 typeerror (flags);
2858         }
2859
2860         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2861          * into the normal, non-optimized stuff.
2862          */
2863         g_push (flags & ~CF_CONST, 0);
2864
2865     }
2866
2867     /* Use long way over the stack */
2868     oper (flags, val, ops);
2869 }
2870
2871
2872
2873 void g_xor (unsigned flags, unsigned long val)
2874 /* Primary = TOS ^ Primary */
2875 {
2876     static char* ops [12] = {
2877         0,              "tosxora0",     "tosxorax",
2878         0,              "tosxora0",     "tosxorax",
2879         0,              0,              "tosxoreax",
2880         0,              0,              "tosxoreax",
2881     };
2882
2883
2884     /* If the right hand side is const, the lhs is not on stack but still
2885      * in the primary register.
2886      */
2887     if (flags & CF_CONST) {
2888
2889         switch (flags & CF_TYPE) {
2890
2891             case CF_CHAR:
2892                 if (flags & CF_FORCECHAR) {
2893                     if ((val & 0xFF) != 0) {
2894                         AddCodeLine ("\teor\t#$%02X", (unsigned char)val);
2895                     }
2896                     return;
2897                 }
2898                 /* FALLTHROUGH */
2899
2900             case CF_INT:
2901                 if (val <= 0xFF) {
2902                     if (val != 0) {
2903                         AddCodeLine ("\teor\t#$%02X", (unsigned char)val);
2904                     }
2905                     return;
2906                 } else if ((val & 0xFF) == 0) {
2907                     AddCodeLine ("\tpha");
2908                     AddCodeLine ("\ttxa");
2909                     AddCodeLine ("\teor\t#$%02X", (unsigned char)(val >> 8));
2910                     AddCodeLine ("\ttax");
2911                     AddCodeLine ("\tpla");
2912                     return;
2913                 }
2914                 break;
2915
2916             case CF_LONG:
2917                 if (val <= 0xFF) {
2918                     if (val != 0) {
2919                         AddCodeLine ("\teor\t#$%02X", (unsigned char)val);
2920                     }
2921                     return;
2922                 }
2923                 break;
2924
2925             default:
2926                 typeerror (flags);
2927         }
2928
2929         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2930          * into the normal, non-optimized stuff.
2931          */
2932         g_push (flags & ~CF_CONST, 0);
2933
2934     }
2935
2936     /* Use long way over the stack */
2937     oper (flags, val, ops);
2938 }
2939
2940
2941
2942 void g_and (unsigned flags, unsigned long val)
2943 /* Primary = TOS & Primary */
2944 {
2945     static char* ops [12] = {
2946         0,              "tosanda0",     "tosandax",
2947         0,              "tosanda0",     "tosandax",
2948         0,              0,              "tosandeax",
2949         0,              0,              "tosandeax",
2950     };
2951
2952     /* If the right hand side is const, the lhs is not on stack but still
2953      * in the primary register.
2954      */
2955     if (flags & CF_CONST) {
2956
2957         switch (flags & CF_TYPE) {
2958
2959             case CF_CHAR:
2960                 if (flags & CF_FORCECHAR) {
2961                     AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
2962                     return;
2963                 }
2964                 /* FALLTHROUGH */
2965             case CF_INT:
2966                 if ((val & 0xFFFF) != 0xFFFF) {
2967                     if (val <= 0xFF) {
2968                         ldxconst (0);
2969                         if (val == 0) {
2970                             ldaconst (0);
2971                         } else if (val != 0xFF) {
2972                             AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
2973                         }
2974                     } else if ((val & 0xFF00) == 0xFF00) {
2975                         AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
2976                     } else if ((val & 0x00FF) == 0x0000) {
2977                         AddCodeLine ("\ttxa");
2978                         AddCodeLine ("\tand\t#$%02X", (unsigned char)(val >> 8));
2979                         AddCodeLine ("\ttax");
2980                         ldaconst (0);
2981                     } else {
2982                         AddCodeLine ("\ttay");
2983                         AddCodeLine ("\ttxa");
2984                         AddCodeLine ("\tand\t#$%02X", (unsigned char)(val >> 8));
2985                         AddCodeLine ("\ttax");
2986                         AddCodeLine ("\ttya");
2987                         if ((val & 0x00FF) != 0x00FF) {
2988                             AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
2989                         }
2990                     }
2991                 }
2992                 return;
2993
2994             case CF_LONG:
2995                 if (val <= 0xFF) {
2996                     ldxconst (0);
2997                     AddCodeLine ("\tstx\tsreg+1");
2998                     AddCodeLine ("\tstx\tsreg");
2999                     if ((val & 0xFF) != 0xFF) {
3000                          AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
3001                     }
3002                     return;
3003                 } else if (val == 0xFF00) {
3004                     ldaconst (0);
3005                     AddCodeLine ("\tsta\tsreg+1");
3006                     AddCodeLine ("\tsta\tsreg");
3007                     return;
3008                 }
3009                 break;
3010
3011             default:
3012                 typeerror (flags);
3013         }
3014
3015         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3016          * into the normal, non-optimized stuff.
3017          */
3018         g_push (flags & ~CF_CONST, 0);
3019
3020     }
3021
3022     /* Use long way over the stack */
3023     oper (flags, val, ops);
3024 }
3025
3026
3027
3028 void g_asr (unsigned flags, unsigned long val)
3029 /* Primary = TOS >> Primary */
3030 {
3031     static char* ops [12] = {
3032         0,              "tosasra0",     "tosasrax",
3033         0,              "tosshra0",     "tosshrax",
3034         0,              0,              "tosasreax",
3035         0,              0,              "tosshreax",
3036     };
3037
3038     /* If the right hand side is const, the lhs is not on stack but still
3039      * in the primary register.
3040      */
3041     if (flags & CF_CONST) {
3042
3043         switch (flags & CF_TYPE) {
3044
3045             case CF_CHAR:
3046             case CF_INT:
3047                 if (val >= 1 && val <= 3) {
3048                     if (flags & CF_UNSIGNED) {
3049                         AddCodeLine ("\tjsr\tshrax%ld", val);
3050                     } else {
3051                         AddCodeLine ("\tjsr\tasrax%ld", val);
3052                     }
3053                     return;
3054                 } else if (val == 8 && (flags & CF_UNSIGNED)) {
3055                     AddCodeLine ("\ttxa");
3056                     ldxconst (0);
3057                     return;
3058                 }
3059                 break;
3060
3061             case CF_LONG:
3062                 if (val >= 1 && val <= 3) {
3063                     if (flags & CF_UNSIGNED) {
3064                         AddCodeLine ("\tjsr\tshreax%ld", val);
3065                     } else {
3066                         AddCodeLine ("\tjsr\tasreax%ld", val);
3067                     }
3068                     return;
3069                 } else if (val == 8 && (flags & CF_UNSIGNED)) {
3070                     AddCodeLine ("\ttxa");
3071                     AddCodeLine ("\tldx\tsreg");
3072                     AddCodeLine ("\tldy\tsreg+1");
3073                     AddCodeLine ("\tsty\tsreg");
3074                     AddCodeLine ("\tldy\t#$00");
3075                     AddCodeLine ("\tsty\tsreg+1");
3076                     return;
3077                 } else if (val == 16) {
3078                     AddCodeLine ("\tldy\t#$00");
3079                     AddCodeLine ("\tldx\tsreg+1");
3080                     if ((flags & CF_UNSIGNED) == 0) {
3081                         AddCodeLine ("\tbpl\t*+3");
3082                         AddCodeLine ("\tdey");
3083                         AddCodeHint ("y:!");
3084                     }
3085                     AddCodeLine ("\tlda\tsreg");
3086                     AddCodeLine ("\tsty\tsreg+1");
3087                     AddCodeLine ("\tsty\tsreg");
3088                     return;
3089                 }
3090                 break;
3091
3092             default:
3093                 typeerror (flags);
3094         }
3095
3096         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3097          * into the normal, non-optimized stuff.
3098          */
3099         g_push (flags & ~CF_CONST, 0);
3100
3101     }
3102
3103     /* Use long way over the stack */
3104     oper (flags, val, ops);
3105 }
3106
3107
3108
3109 void g_asl (unsigned flags, unsigned long val)
3110 /* Primary = TOS << Primary */
3111 {
3112     static char* ops [12] = {
3113         0,              "tosasla0",     "tosaslax",
3114         0,              "tosshla0",     "tosshlax",
3115         0,              0,              "tosasleax",
3116         0,              0,              "tosshleax",
3117     };
3118
3119
3120     /* If the right hand side is const, the lhs is not on stack but still
3121      * in the primary register.
3122      */
3123     if (flags & CF_CONST) {
3124
3125         switch (flags & CF_TYPE) {
3126
3127             case CF_CHAR:
3128             case CF_INT:
3129                 if (val >= 1 && val <= 3) {
3130                     if (flags & CF_UNSIGNED) {
3131                         AddCodeLine ("\tjsr\tshlax%ld", val);
3132                     } else {
3133                         AddCodeLine ("\tjsr\taslax%ld", val);
3134                     }
3135                     return;
3136                 } else if (val == 8) {
3137                     AddCodeLine ("\ttax");
3138                     AddCodeLine ("\tlda\t#$00");
3139                     return;
3140                 }
3141                 break;
3142
3143             case CF_LONG:
3144                 if (val >= 1 && val <= 3) {
3145                     if (flags & CF_UNSIGNED) {
3146                         AddCodeLine ("\tjsr\tshleax%ld", val);
3147                     } else {
3148                         AddCodeLine ("\tjsr\tasleax%ld", val);
3149                     }
3150                     return;
3151                 } else if (val == 8) {
3152                     AddCodeLine ("\tldy\tsreg");
3153                     AddCodeLine ("\tsty\tsreg+1");
3154                     AddCodeLine ("\tstx\tsreg");
3155                     AddCodeLine ("\ttax");
3156                     AddCodeLine ("\tlda\t#$00");
3157                     return;
3158                 } else if (val == 16) {
3159                     AddCodeLine ("\tstx\tsreg+1");
3160                     AddCodeLine ("\tsta\tsreg");
3161                     AddCodeLine ("\tlda\t#$00");
3162                     AddCodeLine ("\ttax");
3163                     return;
3164                 }
3165                 break;
3166
3167             default:
3168                 typeerror (flags);
3169         }
3170
3171         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3172          * into the normal, non-optimized stuff.
3173          */
3174         g_push (flags & ~CF_CONST, 0);
3175
3176     }
3177
3178     /* Use long way over the stack */
3179     oper (flags, val, ops);
3180 }
3181
3182
3183
3184 void g_neg (unsigned flags)
3185 /* Primary = -Primary */
3186 {
3187     switch (flags & CF_TYPE) {
3188
3189         case CF_CHAR:
3190         case CF_INT:
3191             AddCodeLine ("\tjsr\tnegax");
3192             break;
3193
3194         case CF_LONG:
3195             AddCodeLine ("\tjsr\tnegeax");
3196             break;
3197
3198         default:
3199             typeerror (flags);
3200     }
3201 }
3202
3203
3204
3205 void g_bneg (unsigned flags)
3206 /* Primary = !Primary */
3207 {
3208     switch (flags & CF_TYPE) {
3209
3210         case CF_CHAR:
3211             AddCodeLine ("\tjsr\tbnega");
3212             break;
3213
3214         case CF_INT:
3215             AddCodeLine ("\tjsr\tbnegax");
3216             break;
3217
3218         case CF_LONG:
3219             AddCodeLine ("\tjsr\tbnegeax");
3220             break;
3221
3222         default:
3223             typeerror (flags);
3224     }
3225 }
3226
3227
3228
3229 void g_com (unsigned flags)
3230 /* Primary = ~Primary */
3231 {
3232     switch (flags & CF_TYPE) {
3233
3234         case CF_CHAR:
3235         case CF_INT:
3236             AddCodeLine ("\tjsr\tcomplax");
3237             break;
3238
3239         case CF_LONG:
3240             AddCodeLine ("\tjsr\tcompleax");
3241             break;
3242
3243         default:
3244             typeerror (flags);
3245     }
3246 }
3247
3248
3249
3250 void g_inc (unsigned flags, unsigned long val)
3251 /* Increment the primary register by a given number */
3252 {
3253     /* Don't inc by zero */
3254     if (val == 0) {
3255         return;
3256     }
3257
3258     /* Generate code for the supported types */
3259     flags &= ~CF_CONST;
3260     switch (flags & CF_TYPE) {
3261
3262         case CF_CHAR:
3263             if (flags & CF_FORCECHAR) {
3264                 if (CPU == CPU_65C02 && val <= 2) {
3265                     while (val--) {
3266                         AddCodeLine ("\tina");
3267                     }
3268                 } else {
3269                     AddCodeLine ("\tclc");
3270                     AddCodeLine ("\tadc\t#$%02X", (unsigned char)val);
3271                 }
3272                 break;
3273             }
3274             /* FALLTHROUGH */
3275
3276         case CF_INT:
3277             if (CPU == CPU_65C02 && val == 1) {
3278                 AddCodeLine ("\tina");
3279                 AddCodeLine ("\tbne\t*+3");
3280                 AddCodeLine ("\tinx");
3281                 /* Tell the optimizer that the X register may be invalid */
3282                 AddCodeHint ("x:!");
3283             } else if (CodeSizeFactor < 200) {
3284                 /* Use jsr calls */
3285                 if (val <= 8) {
3286                     AddCodeLine ("\tjsr\tincax%lu", val);
3287                 } else if (val <= 255) {
3288                     ldyconst (val);
3289                     AddCodeLine ("\tjsr\tincaxy");
3290                 } else {
3291                     g_add (flags | CF_CONST, val);
3292                 }
3293             } else {
3294                 /* Inline the code */
3295                 if (val < 0x300) {
3296                     if ((val & 0xFF) != 0) {
3297                         AddCodeLine ("\tclc");
3298                         AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
3299                         AddCodeLine ("\tbcc\t*+3");
3300                         AddCodeLine ("\tinx");
3301                         /* Tell the optimizer that the X register may be invalid */
3302                         AddCodeHint ("x:!");
3303                     }
3304                     if (val >= 0x100) {
3305                         AddCodeLine ("\tinx");
3306                     }
3307                     if (val >= 0x200) {
3308                         AddCodeLine ("\tinx");
3309                     }
3310                 } else {
3311                     AddCodeLine ("\tclc");
3312                     if ((val & 0xFF) != 0) {
3313                         AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
3314                         /* Tell the optimizer that the X register may be invalid */
3315                         AddCodeHint ("x:!");
3316                     }
3317                     AddCodeLine ("\tpha");
3318                     AddCodeLine ("\ttxa");
3319                     AddCodeLine ("\tadc\t#$%02X", (unsigned char) (val >> 8));
3320                     AddCodeLine ("\ttax");
3321                     AddCodeLine ("\tpla");
3322                 }
3323             }
3324             break;
3325
3326         case CF_LONG:
3327             if (val <= 255) {
3328                 ldyconst (val);
3329                 AddCodeLine ("\tjsr\tinceaxy");
3330             } else {
3331                 g_add (flags | CF_CONST, val);
3332             }
3333             break;
3334
3335         default:
3336             typeerror (flags);
3337
3338     }
3339 }
3340
3341
3342
3343 void g_dec (unsigned flags, unsigned long val)
3344 /* Decrement the primary register by a given number */
3345 {
3346     /* Don't dec by zero */
3347     if (val == 0) {
3348         return;
3349     }
3350
3351     /* Generate code for the supported types */
3352     flags &= ~CF_CONST;
3353     switch (flags & CF_TYPE) {
3354
3355         case CF_CHAR:
3356             if (flags & CF_FORCECHAR) {
3357                 if (CPU == CPU_65C02 && val <= 2) {
3358                     while (val--) {
3359                         AddCodeLine ("\tdea");
3360                     }
3361                 } else {
3362                     AddCodeLine ("\tsec");
3363                     AddCodeLine ("\tsbc\t#$%02X", (unsigned char)val);
3364                 }
3365                 break;
3366             }
3367             /* FALLTHROUGH */
3368
3369         case CF_INT:
3370             if (CodeSizeFactor < 200) {
3371                 /* Use subroutines */
3372                 if (val <= 8) {
3373                     AddCodeLine ("\tjsr\tdecax%d", (int) val);
3374                 } else if (val <= 255) {
3375                     ldyconst (val);
3376                     AddCodeLine ("\tjsr\tdecaxy");
3377                 } else {
3378                     g_sub (flags | CF_CONST, val);
3379                 }
3380             } else {
3381                 /* Inline the code */
3382                 if (val < 0x300) {
3383                     if ((val & 0xFF) != 0) {
3384                         AddCodeLine ("\tsec");
3385                         AddCodeLine ("\tsbc\t#$%02X", (unsigned char) val);
3386                         AddCodeLine ("\tbcs\t*+3");
3387                         AddCodeLine ("\tdex");
3388                         /* Tell the optimizer that the X register may be invalid */
3389                         AddCodeHint ("x:!");
3390                     }
3391                     if (val >= 0x100) {
3392                         AddCodeLine ("\tdex");
3393                     }
3394                     if (val >= 0x200) {
3395                         AddCodeLine ("\tdex");
3396                     }
3397                 } else {
3398                     AddCodeLine ("\tsec");
3399                     if ((val & 0xFF) != 0) {
3400                         AddCodeLine ("\tsbc\t#$%02X", (unsigned char) val);
3401                         /* Tell the optimizer that the X register may be invalid */
3402                         AddCodeHint ("x:!");
3403                     }
3404                     AddCodeLine ("\tpha");
3405                     AddCodeLine ("\ttxa");
3406                     AddCodeLine ("\tsbc\t#$%02X", (unsigned char) (val >> 8));
3407                     AddCodeLine ("\ttax");
3408                     AddCodeLine ("\tpla");
3409                 }
3410             }
3411             break;
3412
3413         case CF_LONG:
3414             if (val <= 255) {
3415                 ldyconst (val);
3416                 AddCodeLine ("\tjsr\tdeceaxy");
3417             } else {
3418                 g_sub (flags | CF_CONST, val);
3419             }
3420             break;
3421
3422         default:
3423             typeerror (flags);
3424
3425     }
3426 }
3427
3428
3429
3430 /*
3431  * Following are the conditional operators. They compare the TOS against
3432  * the primary and put a literal 1 in the primary if the condition is
3433  * true, otherwise they clear the primary register
3434  */
3435
3436
3437
3438 void g_eq (unsigned flags, unsigned long val)
3439 /* Test for equal */
3440 {
3441     static char* ops [12] = {
3442         "toseq00",      "toseqa0",      "toseqax",
3443         "toseq00",      "toseqa0",      "toseqax",
3444         0,              0,              "toseqeax",
3445         0,              0,              "toseqeax",
3446     };
3447
3448     /* If the right hand side is const, the lhs is not on stack but still
3449      * in the primary register.
3450      */
3451     if (flags & CF_CONST) {
3452
3453         switch (flags & CF_TYPE) {
3454
3455             case CF_CHAR:
3456                 if (flags & CF_FORCECHAR) {
3457                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3458                     AddCodeLine ("\tjsr\tbooleq");
3459                     return;
3460                 }
3461                 /* FALLTHROUGH */
3462
3463             case CF_INT:
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\tbooleq");
3468                 return;
3469
3470             case CF_LONG:
3471                 break;
3472
3473             default:
3474                 typeerror (flags);
3475         }
3476
3477         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3478          * into the normal, non-optimized stuff.
3479          */
3480         g_push (flags & ~CF_CONST, 0);
3481
3482     }
3483
3484     /* Use long way over the stack */
3485     oper (flags, val, ops);
3486 }
3487
3488
3489
3490 void g_ne (unsigned flags, unsigned long val)
3491 /* Test for not equal */
3492 {
3493     static char* ops [12] = {
3494         "tosne00",      "tosnea0",      "tosneax",
3495         "tosne00",      "tosnea0",      "tosneax",
3496         0,              0,              "tosneeax",
3497         0,              0,              "tosneeax",
3498     };
3499
3500
3501     /* If the right hand side is const, the lhs is not on stack but still
3502      * in the primary register.
3503      */
3504     if (flags & CF_CONST) {
3505
3506         switch (flags & CF_TYPE) {
3507
3508             case CF_CHAR:
3509                 if (flags & CF_FORCECHAR) {
3510                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3511                     AddCodeLine ("\tjsr\tboolne");
3512                     return;
3513                 }
3514                 /* FALLTHROUGH */
3515
3516             case CF_INT:
3517                 AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3518                 AddCodeLine ("\tbne\t*+4");
3519                 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3520                 AddCodeLine ("\tjsr\tboolne");
3521                 return;
3522
3523             case CF_LONG:
3524                 break;
3525
3526             default:
3527                 typeerror (flags);
3528         }
3529
3530         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3531          * into the normal, non-optimized stuff.
3532          */
3533         g_push (flags & ~CF_CONST, 0);
3534
3535     }
3536
3537     /* Use long way over the stack */
3538     oper (flags, val, ops);
3539 }
3540
3541
3542
3543 void g_lt (unsigned flags, unsigned long val)
3544 /* Test for less than */
3545 {
3546     static char* ops [12] = {
3547         "toslt00",      "toslta0",      "tosltax",
3548         "tosult00",     "tosulta0",     "tosultax",
3549         0,              0,              "toslteax",
3550         0,              0,              "tosulteax",
3551     };
3552
3553     /* If the right hand side is const, the lhs is not on stack but still
3554      * in the primary register.
3555      */
3556     if (flags & CF_CONST) {
3557
3558         /* Give a warning in some special cases */
3559         if ((flags & CF_UNSIGNED) && val == 0) {
3560             Warning ("Condition is never true");
3561         }
3562
3563         /* Look at the type */
3564         switch (flags & CF_TYPE) {
3565
3566             case CF_CHAR:
3567                 if (flags & CF_FORCECHAR) {
3568                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3569                     if (flags & CF_UNSIGNED) {
3570                         AddCodeLine ("\tjsr\tboolult");
3571                     } else {
3572                         AddCodeLine ("\tjsr\tboollt");
3573                     }
3574                     return;
3575                 }
3576                 /* FALLTHROUGH */
3577
3578             case CF_INT:
3579                 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3580                     /* If we have a signed compare against zero, we only need to
3581                      * test the high byte.
3582                      */
3583                     AddCodeLine ("\ttxa");
3584                     AddCodeLine ("\tjsr\tboollt");
3585                     return;
3586                 }
3587                 /* Direct code only for unsigned data types */
3588                 if (flags & CF_UNSIGNED) {
3589                     AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3590                     AddCodeLine ("\tbne\t*+4");
3591                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3592                     AddCodeLine ("\tjsr\tboolult");
3593                     return;
3594                 }
3595                 break;
3596
3597             case CF_LONG:
3598                 break;
3599
3600             default:
3601                 typeerror (flags);
3602         }
3603
3604         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3605          * into the normal, non-optimized stuff.
3606          */
3607         g_push (flags & ~CF_CONST, 0);
3608
3609     }
3610
3611     /* Use long way over the stack */
3612     oper (flags, val, ops);
3613 }
3614
3615
3616
3617 void g_le (unsigned flags, unsigned long val)
3618 /* Test for less than or equal to */
3619 {
3620     static char* ops [12] = {
3621         "tosle00",      "toslea0",      "tosleax",
3622         "tosule00",     "tosulea0",     "tosuleax",
3623         0,              0,              "tosleeax",
3624         0,              0,              "tosuleeax",
3625     };
3626
3627
3628     /* If the right hand side is const, the lhs is not on stack but still
3629      * in the primary register.
3630      */
3631     if (flags & CF_CONST) {
3632
3633         /* Look at the type */
3634         switch (flags & CF_TYPE) {
3635
3636             case CF_CHAR:
3637                 if (flags & CF_FORCECHAR) {
3638                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3639                     if (flags & CF_UNSIGNED) {
3640                         AddCodeLine ("\tjsr\tboolule");
3641                     } else {
3642                         AddCodeLine ("\tjsr\tboolle");
3643                     }
3644                     return;
3645                 }
3646                 /* FALLTHROUGH */
3647
3648             case CF_INT:
3649                 if (flags & CF_UNSIGNED) {
3650                     AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3651                     AddCodeLine ("\tbne\t*+4");
3652                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3653                     AddCodeLine ("\tjsr\tboolule");
3654                     return;
3655                 }
3656                 break;
3657
3658             case CF_LONG:
3659                 break;
3660
3661             default:
3662                 typeerror (flags);
3663         }
3664
3665         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3666          * into the normal, non-optimized stuff.
3667          */
3668         g_push (flags & ~CF_CONST, 0);
3669
3670     }
3671
3672     /* Use long way over the stack */
3673     oper (flags, val, ops);
3674 }
3675
3676
3677
3678 void g_gt (unsigned flags, unsigned long val)
3679 /* Test for greater than */
3680 {
3681     static char* ops [12] = {
3682         "tosgt00",      "tosgta0",      "tosgtax",
3683         "tosugt00",     "tosugta0",     "tosugtax",
3684         0,              0,              "tosgteax",
3685         0,              0,              "tosugteax",
3686     };
3687
3688
3689     /* If the right hand side is const, the lhs is not on stack but still
3690      * in the primary register.
3691      */
3692     if (flags & CF_CONST) {
3693
3694         /* Look at the type */
3695         switch (flags & CF_TYPE) {
3696
3697             case CF_CHAR:
3698                 if (flags & CF_FORCECHAR) {
3699                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3700                     if (flags & CF_UNSIGNED) {
3701                         /* If we have a compare > 0, we will replace it by
3702                          * != 0 here, since both are identical but the latter
3703                          * is easier to optimize.
3704                          */
3705                         if (val & 0xFF) {
3706                             AddCodeLine ("\tjsr\tboolugt");
3707                         } else {
3708                             AddCodeLine ("\tjsr\tboolne");
3709                         }
3710                     } else {
3711                         AddCodeLine ("\tjsr\tboolgt");
3712                     }
3713                     return;
3714                 }
3715                 /* FALLTHROUGH */
3716
3717             case CF_INT:
3718                 if (flags & CF_UNSIGNED) {
3719                     /* If we have a compare > 0, we will replace it by
3720                      * != 0 here, since both are identical but the latter
3721                      * is easier to optimize.
3722                      */
3723                     if ((val & 0xFFFF) == 0) {
3724                         AddCodeLine ("\tstx\ttmp1");
3725                         AddCodeLine ("\tora\ttmp1");
3726                         AddCodeLine ("\tjsr\tboolne");
3727                     } else {
3728                         AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3729                         AddCodeLine ("\tbne\t*+4");
3730                         AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3731                         AddCodeLine ("\tjsr\tboolugt");
3732                     }
3733                     return;
3734                 }
3735                 break;
3736
3737             case CF_LONG:
3738                 break;
3739
3740             default:
3741                 typeerror (flags);
3742         }
3743
3744         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3745          * into the normal, non-optimized stuff.
3746          */
3747         g_push (flags & ~CF_CONST, 0);
3748
3749     }
3750
3751     /* Use long way over the stack */
3752     oper (flags, val, ops);
3753 }
3754
3755
3756
3757 void g_ge (unsigned flags, unsigned long val)
3758 /* Test for greater than or equal to */
3759 {
3760     static char* ops [12] = {
3761         "tosge00",      "tosgea0",      "tosgeax",
3762         "tosuge00",     "tosugea0",     "tosugeax",
3763         0,              0,              "tosgeeax",
3764         0,              0,              "tosugeeax",
3765     };
3766
3767
3768     /* If the right hand side is const, the lhs is not on stack but still
3769      * in the primary register.
3770      */
3771     if (flags & CF_CONST) {
3772
3773         /* Give a warning in some special cases */
3774         if ((flags & CF_UNSIGNED) && val == 0) {
3775             Warning ("Condition is always true");
3776         }
3777
3778         /* Look at the type */
3779         switch (flags & CF_TYPE) {
3780
3781             case CF_CHAR:
3782                 if (flags & CF_FORCECHAR) {
3783                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3784                     if (flags & CF_UNSIGNED) {
3785                         AddCodeLine ("\tjsr\tbooluge");
3786                     } else {
3787                         AddCodeLine ("\tjsr\tboolge");
3788                     }
3789                     return;
3790                 }
3791                 /* FALLTHROUGH */
3792
3793             case CF_INT:
3794                 if (flags & CF_UNSIGNED) {
3795                     AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3796                     AddCodeLine ("\tbne\t*+4");
3797                     AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3798                     AddCodeLine ("\tjsr\tbooluge");
3799                     return;
3800                 }
3801                 break;
3802
3803             case CF_LONG:
3804                 break;
3805
3806             default:
3807                 typeerror (flags);
3808         }
3809
3810         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3811          * into the normal, non-optimized stuff.
3812          */
3813         g_push (flags & ~CF_CONST, 0);
3814
3815     }
3816
3817     /* Use long way over the stack */
3818     oper (flags, val, ops);
3819 }
3820
3821
3822
3823 /*****************************************************************************/
3824 /*                         Allocating static storage                         */
3825 /*****************************************************************************/
3826
3827
3828
3829 void g_res (unsigned n)
3830 /* Reserve static storage, n bytes */
3831 {
3832     AddCodeLine ("\t.res\t%u,$00", n);
3833 }
3834
3835
3836
3837 void g_defdata (unsigned flags, unsigned long val, unsigned offs)
3838 /* Define data with the size given in flags */
3839 {
3840     if (flags & CF_CONST) {
3841
3842         /* Numeric constant */
3843         switch (flags & CF_TYPE) {
3844
3845             case CF_CHAR:
3846                 AddCodeLine ("\t.byte\t$%02lX", val & 0xFF);
3847                 break;
3848
3849             case CF_INT:
3850                 AddCodeLine ("\t.word\t$%04lX", val & 0xFFFF);
3851                 break;
3852
3853             case CF_LONG:
3854                 AddCodeLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
3855                 break;
3856
3857             default:
3858                 typeerror (flags);
3859                 break;
3860
3861         }
3862
3863     } else {
3864
3865         /* Create the correct label name */
3866         const char* Label = GetLabelName (flags, val, offs);
3867
3868         /* Labels are always 16 bit */
3869         AddCodeLine ("\t.word\t%s", Label);
3870
3871     }
3872 }
3873
3874
3875
3876 void g_defbytes (const void* Bytes, unsigned Count)
3877 /* Output a row of bytes as a constant */
3878 {
3879     unsigned Chunk;
3880     char Buf [128];
3881     char* B;
3882
3883     /* Cast the buffer pointer */
3884     const unsigned char* Data = (const unsigned char*) Bytes;
3885
3886     /* Output the stuff */
3887     while (Count) {
3888
3889         /* How many go into this line? */
3890         if ((Chunk = Count) > 16) {
3891             Chunk = 16;
3892         }
3893         Count -= Chunk;
3894
3895         /* Output one line */
3896         strcpy (Buf, "\t.byte\t");
3897         B = Buf + 7;
3898         do {
3899             B += sprintf (B, "$%02X", *Data++);
3900             if (--Chunk) {
3901                 *B++ = ',';
3902             }
3903         } while (Chunk);
3904
3905         /* Output the line */
3906         AddCodeLine (Buf);
3907     }
3908 }
3909
3910
3911
3912 void g_zerobytes (unsigned n)
3913 /* Output n bytes of data initialized with zero */
3914 {
3915     AddCodeLine ("\t.res\t%u,$00", n);
3916 }
3917
3918
3919
3920 /*****************************************************************************/
3921 /*                          Inlined known functions                          */
3922 /*****************************************************************************/
3923
3924
3925
3926 void g_strlen (unsigned flags, unsigned long val, unsigned offs)
3927 /* Inline the strlen() function */
3928 {
3929     /* We need a label in both cases */
3930     unsigned label = GetLocalLabel ();
3931
3932     /* Two different encodings */
3933     if (flags & CF_CONST) {
3934
3935         /* The address of the string is constant. Create the correct label name */
3936         char* lbuf = GetLabelName (flags, val, offs);
3937
3938         /* Generate the strlen code */
3939         AddCodeLine ("\tldy\t#$FF");
3940         g_defloclabel (label);
3941         AddCodeLine ("\tiny");
3942         AddCodeLine ("\tlda\t%s,y", lbuf);
3943         AddCodeLine ("\tbne\tL%04X", label);
3944         AddCodeLine ("\ttax");
3945         AddCodeLine ("\ttya");
3946
3947     } else {
3948
3949         /* Address not constant but in primary */
3950         if (CodeSizeFactor < 400) {
3951             /* This is too much code, so call strlen instead of inlining */
3952             AddCodeLine ("\tjsr\t_strlen");
3953         } else {
3954             /* Inline the function */
3955             AddCodeLine ("\tsta\tptr1");
3956             AddCodeLine ("\tstx\tptr1+1");
3957             AddCodeLine ("\tldy\t#$FF");
3958             g_defloclabel (label);
3959             AddCodeLine ("\tiny");
3960             AddCodeLine ("\tlda\t(ptr1),y");
3961             AddCodeLine ("\tbne\tL%04X", label);
3962             AddCodeLine ("\ttax");
3963             AddCodeLine ("\ttya");
3964         }
3965     }
3966 }
3967
3968
3969