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