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