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