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