]> git.sur5r.net Git - cc65/blob - src/cc65/codegen.c
dc0fd520d0b282167b8fd674cc4fe8c8c17ac482
[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 (IS_Get (&CodeSizeFactor) >= (long) (val+1)*130) {
3123                         AddCodeLine ("stx tmp1");
3124                         while (val--) {
3125                             AddCodeLine ("asl a");
3126                             AddCodeLine ("rol tmp1");
3127                         }
3128                         AddCodeLine ("ldx tmp1");
3129                     } else {
3130                         if (flags & CF_UNSIGNED) {
3131                             AddCodeLine ("jsr shlax%ld", val);
3132                         } else {
3133                             AddCodeLine ("jsr aslax%ld", val);
3134                         }
3135                     }
3136                     return;
3137                 }
3138                 break;
3139
3140             case CF_LONG:
3141                 if (val == 0) {
3142                     /* Nothing to do */
3143                     return;
3144                 } else if (val >= 1 && val <= 4) {
3145                     if (flags & CF_UNSIGNED) {
3146                         AddCodeLine ("jsr shleax%ld", val);
3147                     } else {
3148                         AddCodeLine ("jsr asleax%ld", val);
3149                     }
3150                     return;
3151                 } else if (val == 8) {
3152                     AddCodeLine ("ldy sreg");
3153                     AddCodeLine ("sty sreg+1");
3154                     AddCodeLine ("stx sreg");
3155                     AddCodeLine ("tax");
3156                     AddCodeLine ("lda #$00");
3157                     return;
3158                 } else if (val == 16) {
3159                     AddCodeLine ("stx sreg+1");
3160                     AddCodeLine ("sta sreg");
3161                     AddCodeLine ("lda #$00");
3162                     AddCodeLine ("tax");
3163                     return;
3164                 }
3165                 break;
3166
3167             default:
3168                 typeerror (flags);
3169         }
3170
3171         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3172          * into the normal, non-optimized stuff. Note: The standard stuff will
3173          * always work with ints.
3174          */
3175         flags &= ~CF_FORCECHAR;
3176         g_push (flags & ~CF_CONST, 0);
3177     }
3178
3179     /* Use long way over the stack */
3180     oper (flags, val, ops);
3181 }
3182
3183
3184
3185 void g_neg (unsigned Flags)
3186 /* Primary = -Primary */
3187 {
3188     switch (Flags & CF_TYPE) {
3189
3190         case CF_CHAR:
3191             if (Flags & CF_FORCECHAR) {
3192                 AddCodeLine ("eor #$FF");
3193                 AddCodeLine ("clc");
3194                 AddCodeLine ("adc #$01");
3195                 return;
3196             }
3197             /* FALLTHROUGH */
3198
3199         case CF_INT:
3200             AddCodeLine ("jsr negax");
3201             break;
3202
3203         case CF_LONG:
3204             AddCodeLine ("jsr negeax");
3205             break;
3206
3207         default:
3208             typeerror (Flags);
3209     }
3210 }
3211
3212
3213
3214 void g_bneg (unsigned flags)
3215 /* Primary = !Primary */
3216 {
3217     switch (flags & CF_TYPE) {
3218
3219         case CF_CHAR:
3220             AddCodeLine ("jsr bnega");
3221             break;
3222
3223         case CF_INT:
3224             AddCodeLine ("jsr bnegax");
3225             break;
3226
3227         case CF_LONG:
3228             AddCodeLine ("jsr bnegeax");
3229             break;
3230
3231         default:
3232             typeerror (flags);
3233     }
3234 }
3235
3236
3237
3238 void g_com (unsigned Flags)
3239 /* Primary = ~Primary */
3240 {
3241     switch (Flags & CF_TYPE) {
3242
3243         case CF_CHAR:
3244             if (Flags & CF_FORCECHAR) {
3245                 AddCodeLine ("eor #$FF");
3246                 return;
3247             }
3248             /* FALLTHROUGH */
3249
3250         case CF_INT:
3251             AddCodeLine ("jsr complax");
3252             break;
3253
3254         case CF_LONG:
3255             AddCodeLine ("jsr compleax");
3256             break;
3257
3258         default:
3259             typeerror (Flags);
3260     }
3261 }
3262
3263
3264
3265 void g_inc (unsigned flags, unsigned long val)
3266 /* Increment the primary register by a given number */
3267 {
3268     /* Don't inc by zero */
3269     if (val == 0) {
3270         return;
3271     }
3272
3273     /* Generate code for the supported types */
3274     flags &= ~CF_CONST;
3275     switch (flags & CF_TYPE) {
3276
3277         case CF_CHAR:
3278             if (flags & CF_FORCECHAR) {
3279                 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val <= 2) {
3280                     while (val--) {
3281                         AddCodeLine ("ina");
3282                     }
3283                 } else {
3284                     AddCodeLine ("clc");
3285                     AddCodeLine ("adc #$%02X", (unsigned char)val);
3286                 }
3287                 break;
3288             }
3289             /* FALLTHROUGH */
3290
3291         case CF_INT:
3292             if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val == 1) {
3293                 unsigned L = GetLocalLabel();
3294                 AddCodeLine ("ina");
3295                 AddCodeLine ("bne %s", LocalLabelName (L));
3296                 AddCodeLine ("inx");
3297                 g_defcodelabel (L);
3298             } else if (IS_Get (&CodeSizeFactor) < 200) {
3299                 /* Use jsr calls */
3300                 if (val <= 8) {
3301                     AddCodeLine ("jsr incax%lu", val);
3302                 } else if (val <= 255) {
3303                     ldyconst (val);
3304                     AddCodeLine ("jsr incaxy");
3305                 } else {
3306                     g_add (flags | CF_CONST, val);
3307                 }
3308             } else {
3309                 /* Inline the code */
3310                 if (val <= 0x300) {
3311                     if ((val & 0xFF) != 0) {
3312                         unsigned L = GetLocalLabel();
3313                         AddCodeLine ("clc");
3314                         AddCodeLine ("adc #$%02X", (unsigned char) val);
3315                         AddCodeLine ("bcc %s", LocalLabelName (L));
3316                         AddCodeLine ("inx");
3317                         g_defcodelabel (L);
3318                     }
3319                     if (val >= 0x100) {
3320                         AddCodeLine ("inx");
3321                     }
3322                     if (val >= 0x200) {
3323                         AddCodeLine ("inx");
3324                     }
3325                     if (val >= 0x300) {
3326                         AddCodeLine ("inx");
3327                     }
3328                 } else {
3329                     AddCodeLine ("clc");
3330                     if ((val & 0xFF) != 0) {
3331                         AddCodeLine ("adc #$%02X", (unsigned char) val);
3332                     }
3333                     AddCodeLine ("pha");
3334                     AddCodeLine ("txa");
3335                     AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3336                     AddCodeLine ("tax");
3337                     AddCodeLine ("pla");
3338                 }
3339             }
3340             break;
3341
3342         case CF_LONG:
3343             if (val <= 255) {
3344                 ldyconst (val);
3345                 AddCodeLine ("jsr inceaxy");
3346             } else {
3347                 g_add (flags | CF_CONST, val);
3348             }
3349             break;
3350
3351         default:
3352             typeerror (flags);
3353
3354     }
3355 }
3356
3357
3358
3359 void g_dec (unsigned flags, unsigned long val)
3360 /* Decrement the primary register by a given number */
3361 {
3362     /* Don't dec by zero */
3363     if (val == 0) {
3364         return;
3365     }
3366
3367     /* Generate code for the supported types */
3368     flags &= ~CF_CONST;
3369     switch (flags & CF_TYPE) {
3370
3371         case CF_CHAR:
3372             if (flags & CF_FORCECHAR) {
3373                 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val <= 2) {
3374                     while (val--) {
3375                         AddCodeLine ("dea");
3376                     }
3377                 } else {
3378                     AddCodeLine ("sec");
3379                     AddCodeLine ("sbc #$%02X", (unsigned char)val);
3380                 }
3381                 break;
3382             }
3383             /* FALLTHROUGH */
3384
3385         case CF_INT:
3386             if (IS_Get (&CodeSizeFactor) < 200) {
3387                 /* Use subroutines */
3388                 if (val <= 8) {
3389                     AddCodeLine ("jsr decax%d", (int) val);
3390                 } else if (val <= 255) {
3391                     ldyconst (val);
3392                     AddCodeLine ("jsr decaxy");
3393                 } else {
3394                     g_sub (flags | CF_CONST, val);
3395                 }
3396             } else {
3397                 /* Inline the code */
3398                 if (val < 0x300) {
3399                     if ((val & 0xFF) != 0) {
3400                         unsigned L = GetLocalLabel();
3401                         AddCodeLine ("sec");
3402                         AddCodeLine ("sbc #$%02X", (unsigned char) val);
3403                         AddCodeLine ("bcs %s", LocalLabelName (L));
3404                         AddCodeLine ("dex");
3405                         g_defcodelabel (L);
3406                     }
3407                     if (val >= 0x100) {
3408                         AddCodeLine ("dex");
3409                     }
3410                     if (val >= 0x200) {
3411                         AddCodeLine ("dex");
3412                     }
3413                 } else {
3414                     AddCodeLine ("sec");
3415                     if ((val & 0xFF) != 0) {
3416                         AddCodeLine ("sbc #$%02X", (unsigned char) val);
3417                     }
3418                     AddCodeLine ("pha");
3419                     AddCodeLine ("txa");
3420                     AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3421                     AddCodeLine ("tax");
3422                     AddCodeLine ("pla");
3423                 }
3424             }
3425             break;
3426
3427         case CF_LONG:
3428             if (val <= 255) {
3429                 ldyconst (val);
3430                 AddCodeLine ("jsr deceaxy");
3431             } else {
3432                 g_sub (flags | CF_CONST, val);
3433             }
3434             break;
3435
3436         default:
3437             typeerror (flags);
3438
3439     }
3440 }
3441
3442
3443
3444 /*
3445  * Following are the conditional operators. They compare the TOS against
3446  * the primary and put a literal 1 in the primary if the condition is
3447  * true, otherwise they clear the primary register
3448  */
3449
3450
3451
3452 void g_eq (unsigned flags, unsigned long val)
3453 /* Test for equal */
3454 {
3455     static char* ops [12] = {
3456         "toseq00",      "toseqa0",      "toseqax",
3457         "toseq00",      "toseqa0",      "toseqax",
3458         0,              0,              "toseqeax",
3459         0,              0,              "toseqeax",
3460     };
3461
3462     unsigned L;
3463
3464     /* If the right hand side is const, the lhs is not on stack but still
3465      * in the primary register.
3466      */
3467     if (flags & CF_CONST) {
3468
3469         switch (flags & CF_TYPE) {
3470
3471             case CF_CHAR:
3472                 if (flags & CF_FORCECHAR) {
3473                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3474                     AddCodeLine ("jsr booleq");
3475                     return;
3476                 }
3477                 /* FALLTHROUGH */
3478
3479             case CF_INT:
3480                 L = GetLocalLabel();
3481                 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3482                 AddCodeLine ("bne %s", LocalLabelName (L));
3483                 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3484                 g_defcodelabel (L);
3485                 AddCodeLine ("jsr booleq");
3486                 return;
3487
3488             case CF_LONG:
3489                 break;
3490
3491             default:
3492                 typeerror (flags);
3493         }
3494
3495         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3496          * into the normal, non-optimized stuff. Note: The standard stuff will
3497          * always work with ints.
3498          */
3499         flags &= ~CF_FORCECHAR;
3500         g_push (flags & ~CF_CONST, 0);
3501     }
3502
3503     /* Use long way over the stack */
3504     oper (flags, val, ops);
3505 }
3506
3507
3508
3509 void g_ne (unsigned flags, unsigned long val)
3510 /* Test for not equal */
3511 {
3512     static char* ops [12] = {
3513         "tosne00",      "tosnea0",      "tosneax",
3514         "tosne00",      "tosnea0",      "tosneax",
3515         0,              0,              "tosneeax",
3516         0,              0,              "tosneeax",
3517     };
3518
3519     unsigned L;
3520
3521     /* If the right hand side is const, the lhs is not on stack but still
3522      * in the primary register.
3523      */
3524     if (flags & CF_CONST) {
3525
3526         switch (flags & CF_TYPE) {
3527
3528             case CF_CHAR:
3529                 if (flags & CF_FORCECHAR) {
3530                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3531                     AddCodeLine ("jsr boolne");
3532                     return;
3533                 }
3534                 /* FALLTHROUGH */
3535
3536             case CF_INT:
3537                 L = GetLocalLabel();
3538                 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3539                 AddCodeLine ("bne %s", LocalLabelName (L));
3540                 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3541                 g_defcodelabel (L);
3542                 AddCodeLine ("jsr boolne");
3543                 return;
3544
3545             case CF_LONG:
3546                 break;
3547
3548             default:
3549                 typeerror (flags);
3550         }
3551
3552         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3553          * into the normal, non-optimized stuff. Note: The standard stuff will
3554          * always work with ints.
3555          */
3556         flags &= ~CF_FORCECHAR;
3557         g_push (flags & ~CF_CONST, 0);
3558     }
3559
3560     /* Use long way over the stack */
3561     oper (flags, val, ops);
3562 }
3563
3564
3565
3566 void g_lt (unsigned flags, unsigned long val)
3567 /* Test for less than */
3568 {
3569     static char* ops [12] = {
3570         "toslt00",      "toslta0",      "tosltax",
3571         "tosult00",     "tosulta0",     "tosultax",
3572         0,              0,              "toslteax",
3573         0,              0,              "tosulteax",
3574     };
3575
3576     /* If the right hand side is const, the lhs is not on stack but still
3577      * in the primary register.
3578      */
3579     if (flags & CF_CONST) {
3580
3581         /* Because the handling of the overflow flag is too complex for
3582          * inlining, we can handle only unsigned compares, and signed
3583          * compares against zero here.
3584          */
3585         if (flags & CF_UNSIGNED) {
3586
3587             /* Give a warning in some special cases */
3588             if (val == 0) {
3589                 Warning ("Condition is never true");
3590                 AddCodeLine ("jsr return0");
3591                 return;
3592             }
3593
3594             /* Look at the type */
3595             switch (flags & CF_TYPE) {
3596
3597                 case CF_CHAR:
3598                     if (flags & CF_FORCECHAR) {
3599                         AddCodeLine ("cmp #$%02X", (unsigned char)val);
3600                         AddCodeLine ("jsr boolult");
3601                         return;
3602                     }
3603                     /* FALLTHROUGH */
3604
3605                 case CF_INT:
3606                     /* If the low byte is zero, we must only test the high byte */
3607                     AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3608                     if ((val & 0xFF) != 0) {
3609                         unsigned L = GetLocalLabel();
3610                         AddCodeLine ("bne %s", LocalLabelName (L));
3611                         AddCodeLine ("cmp #$%02X", (unsigned char)val);
3612                         g_defcodelabel (L);
3613                     }
3614                     AddCodeLine ("jsr boolult");
3615                     return;
3616
3617                 case CF_LONG:
3618                     /* Do a subtraction */
3619                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3620                     AddCodeLine ("txa");
3621                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
3622                     AddCodeLine ("lda sreg");
3623                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 16));
3624                     AddCodeLine ("lda sreg+1");
3625                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 24));
3626                     AddCodeLine ("jsr boolult");
3627                     return;
3628
3629                 default:
3630                     typeerror (flags);
3631             }
3632
3633         } else if (val == 0) {
3634
3635             /* Look at the type */
3636             switch (flags & CF_TYPE) {
3637
3638                 case CF_CHAR:
3639                     if (flags & CF_FORCECHAR) {
3640                         AddCodeLine ("tax");
3641                         AddCodeLine ("jsr boollt");
3642                         return;
3643                     }
3644                     /* FALLTHROUGH */
3645
3646                 case CF_INT:
3647                     /* Just check the high byte */
3648                     AddCodeLine ("txa");
3649                     AddCodeLine ("jsr boollt");
3650                     return;
3651
3652                 case CF_LONG:
3653                     /* Just check the high byte */
3654                     AddCodeLine ("lda sreg+1");
3655                     AddCodeLine ("jsr boollt");
3656                     return;
3657
3658                 default:
3659                     typeerror (flags);
3660             }
3661         }
3662
3663         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3664          * into the normal, non-optimized stuff. Note: The standard stuff will
3665          * always work with ints.
3666          */
3667         flags &= ~CF_FORCECHAR;
3668         g_push (flags & ~CF_CONST, 0);
3669     }
3670
3671     /* Use long way over the stack */
3672     oper (flags, val, ops);
3673 }
3674
3675
3676
3677 void g_le (unsigned flags, unsigned long val)
3678 /* Test for less than or equal to */
3679 {
3680     static char* ops [12] = {
3681         "tosle00",      "toslea0",      "tosleax",
3682         "tosule00",     "tosulea0",     "tosuleax",
3683         0,              0,              "tosleeax",
3684         0,              0,              "tosuleeax",
3685     };
3686
3687
3688     /* If the right hand side is const, the lhs is not on stack but still
3689      * in the primary register.
3690      */
3691     if (flags & CF_CONST) {
3692
3693         /* Look at the type */
3694         switch (flags & CF_TYPE) {
3695
3696             case CF_CHAR:
3697                 if (flags & CF_FORCECHAR) {
3698                     if (flags & CF_UNSIGNED) {
3699                         /* Unsigned compare */
3700                         if (val < 0xFF) {
3701                             /* Use < instead of <= because the former gives
3702                              * better code on the 6502 than the latter.
3703                              */
3704                             g_lt (flags, val+1);
3705                         } else {
3706                             /* Always true */
3707                             Warning ("Condition is always true");
3708                             AddCodeLine ("jsr return1");
3709                         }
3710                     } else {
3711                         /* Signed compare */
3712                         if ((long) val < 0x7F) {
3713                             /* Use < instead of <= because the former gives
3714                              * better code on the 6502 than the latter.
3715                              */
3716                             g_lt (flags, val+1);
3717                         } else {
3718                             /* Always true */
3719                             Warning ("Condition is always true");
3720                             AddCodeLine ("jsr return1");
3721                         }
3722                     }
3723                     return;
3724                 }
3725                 /* FALLTHROUGH */
3726
3727             case CF_INT:
3728                 if (flags & CF_UNSIGNED) {
3729                     /* Unsigned compare */
3730                     if (val < 0xFFFF) {
3731                         /* Use < instead of <= because the former gives
3732                          * better code on the 6502 than the latter.
3733                          */
3734                         g_lt (flags, val+1);
3735                     } else {
3736                         /* Always true */
3737                         Warning ("Condition is always true");
3738                         AddCodeLine ("jsr return1");
3739                     }
3740                 } else {
3741                     /* Signed compare */
3742                     if ((long) val < 0x7FFF) {
3743                         g_lt (flags, val+1);
3744                     } else {
3745                         /* Always true */
3746                         Warning ("Condition is always true");
3747                         AddCodeLine ("jsr return1");
3748                     }
3749                 }
3750                 return;
3751
3752             case CF_LONG:
3753                 if (flags & CF_UNSIGNED) {
3754                     /* Unsigned compare */
3755                     if (val < 0xFFFFFFFF) {
3756                         /* Use < instead of <= because the former gives
3757                          * better code on the 6502 than the latter.
3758                          */
3759                         g_lt (flags, val+1);
3760                     } else {
3761                         /* Always true */
3762                         Warning ("Condition is always true");
3763                         AddCodeLine ("jsr return1");
3764                     }
3765                 } else {
3766                     /* Signed compare */
3767                     if ((long) val < 0x7FFFFFFF) {
3768                         g_lt (flags, val+1);
3769                     } else {
3770                         /* Always true */
3771                         Warning ("Condition is always true");
3772                         AddCodeLine ("jsr return1");
3773                     }
3774                 }
3775                 return;
3776
3777             default:
3778                 typeerror (flags);
3779         }
3780
3781         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3782          * into the normal, non-optimized stuff. Note: The standard stuff will
3783          * always work with ints.
3784          */
3785         flags &= ~CF_FORCECHAR;
3786         g_push (flags & ~CF_CONST, 0);
3787     }
3788
3789     /* Use long way over the stack */
3790     oper (flags, val, ops);
3791 }
3792
3793
3794
3795 void g_gt (unsigned flags, unsigned long val)
3796 /* Test for greater than */
3797 {
3798     static char* ops [12] = {
3799         "tosgt00",      "tosgta0",      "tosgtax",
3800         "tosugt00",     "tosugta0",     "tosugtax",
3801         0,              0,              "tosgteax",
3802         0,              0,              "tosugteax",
3803     };
3804
3805
3806     /* If the right hand side is const, the lhs is not on stack but still
3807      * in the primary register.
3808      */
3809     if (flags & CF_CONST) {
3810
3811         /* Look at the type */
3812         switch (flags & CF_TYPE) {
3813
3814             case CF_CHAR:
3815                 if (flags & CF_FORCECHAR) {
3816                     if (flags & CF_UNSIGNED) {
3817                         if (val == 0) {
3818                             /* If we have a compare > 0, we will replace it by
3819                              * != 0 here, since both are identical but the
3820                              * latter is easier to optimize.
3821                              */
3822                             g_ne (flags, val);
3823                         } else if (val < 0xFF) {
3824                             /* Use >= instead of > because the former gives
3825                              * better code on the 6502 than the latter.
3826                              */
3827                             g_ge (flags, val+1);
3828                         } else {
3829                             /* Never true */
3830                             Warning ("Condition is never true");
3831                             AddCodeLine ("jsr return0");
3832                         }
3833                     } else {
3834                         if ((long) val < 0x7F) {
3835                             /* Use >= instead of > because the former gives
3836                              * better code on the 6502 than the latter.
3837                              */
3838                             g_ge (flags, val+1);
3839                         } else {
3840                             /* Never true */
3841                             Warning ("Condition is never true");
3842                             AddCodeLine ("jsr return0");
3843                         }
3844                     }
3845                     return;
3846                 }
3847                 /* FALLTHROUGH */
3848
3849             case CF_INT:
3850                 if (flags & CF_UNSIGNED) {
3851                     /* Unsigned compare */
3852                     if (val == 0) {
3853                         /* If we have a compare > 0, we will replace it by
3854                          * != 0 here, since both are identical but the latter
3855                          * is easier to optimize.
3856                          */
3857                         g_ne (flags, val);
3858                     } else if (val < 0xFFFF) {
3859                         /* Use >= instead of > because the former gives better
3860                          * code on the 6502 than the latter.
3861                          */
3862                         g_ge (flags, val+1);
3863                     } else {
3864                         /* Never true */
3865                         Warning ("Condition is never true");
3866                         AddCodeLine ("jsr return0");
3867                     }
3868                 } else {
3869                     /* Signed compare */
3870                     if ((long) val < 0x7FFF) {
3871                         g_ge (flags, val+1);
3872                     } else {
3873                         /* Never true */
3874                         Warning ("Condition is never true");
3875                         AddCodeLine ("jsr return0");
3876                     }
3877                 }
3878                 return;
3879
3880             case CF_LONG:
3881                 if (flags & CF_UNSIGNED) {
3882                     /* Unsigned compare */
3883                     if (val == 0) {
3884                         /* If we have a compare > 0, we will replace it by
3885                          * != 0 here, since both are identical but the latter
3886                          * is easier to optimize.
3887                          */
3888                         g_ne (flags, val);
3889                     } else if (val < 0xFFFFFFFF) {
3890                         /* Use >= instead of > because the former gives better
3891                          * code on the 6502 than the latter.
3892                          */
3893                         g_ge (flags, val+1);
3894                     } else {
3895                         /* Never true */
3896                         Warning ("Condition is never true");
3897                         AddCodeLine ("jsr return0");
3898                     }
3899                 } else {
3900                     /* Signed compare */
3901                     if ((long) val < 0x7FFFFFFF) {
3902                         g_ge (flags, val+1);
3903                     } else {
3904                         /* Never true */
3905                         Warning ("Condition is never true");
3906                         AddCodeLine ("jsr return0");
3907                     }
3908                 }
3909                 return;
3910
3911             default:
3912                 typeerror (flags);
3913         }
3914
3915         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3916          * into the normal, non-optimized stuff. Note: The standard stuff will
3917          * always work with ints.
3918          */
3919         flags &= ~CF_FORCECHAR;
3920         g_push (flags & ~CF_CONST, 0);
3921     }
3922
3923     /* Use long way over the stack */
3924     oper (flags, val, ops);
3925 }
3926
3927
3928
3929 void g_ge (unsigned flags, unsigned long val)
3930 /* Test for greater than or equal to */
3931 {
3932     static char* ops [12] = {
3933         "tosge00",      "tosgea0",      "tosgeax",
3934         "tosuge00",     "tosugea0",     "tosugeax",
3935         0,              0,              "tosgeeax",
3936         0,              0,              "tosugeeax",
3937     };
3938
3939
3940     /* If the right hand side is const, the lhs is not on stack but still
3941      * in the primary register.
3942      */
3943     if (flags & CF_CONST) {
3944
3945         /* Because the handling of the overflow flag is too complex for
3946          * inlining, we can handle only unsigned compares, and signed
3947          * compares against zero here.
3948          */
3949         if (flags & CF_UNSIGNED) {
3950
3951             /* Give a warning in some special cases */
3952             if (val == 0) {
3953                 Warning ("Condition is always true");
3954                 AddCodeLine ("jsr return1");
3955                 return;
3956             }
3957
3958             /* Look at the type */
3959             switch (flags & CF_TYPE) {
3960
3961                 case CF_CHAR:
3962                     if (flags & CF_FORCECHAR) {
3963                         AddCodeLine ("cmp #$%02X", (unsigned char)val);
3964                         AddCodeLine ("jsr booluge");
3965                         return;
3966                     }
3967                     /* FALLTHROUGH */
3968
3969                 case CF_INT:
3970                     /* If the low byte is zero, we must only test the high byte */
3971                     AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3972                     if ((val & 0xFF) != 0) {
3973                         unsigned L = GetLocalLabel();
3974                         AddCodeLine ("bne %s", LocalLabelName (L));
3975                         AddCodeLine ("cmp #$%02X", (unsigned char)val);
3976                         g_defcodelabel (L);
3977                     }
3978                     AddCodeLine ("jsr booluge");
3979                     return;
3980
3981                 case CF_LONG:
3982                     /* Do a subtraction */
3983                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3984                     AddCodeLine ("txa");
3985                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
3986                     AddCodeLine ("lda sreg");
3987                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 16));
3988                     AddCodeLine ("lda sreg+1");
3989                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 24));
3990                     AddCodeLine ("jsr booluge");
3991                     return;
3992
3993                 default:
3994                     typeerror (flags);
3995             }
3996
3997         } else if (val == 0) {
3998
3999             /* Look at the type */
4000             switch (flags & CF_TYPE) {
4001
4002                 case CF_CHAR:
4003                     if (flags & CF_FORCECHAR) {
4004                         AddCodeLine ("tax");
4005                         AddCodeLine ("jsr boolge");
4006                         return;
4007                     }
4008                     /* FALLTHROUGH */
4009
4010                 case CF_INT:
4011                     /* Just test the high byte */
4012                     AddCodeLine ("txa");
4013                     AddCodeLine ("jsr boolge");
4014                     return;
4015
4016                 case CF_LONG:
4017                     /* Just test the high byte */
4018                     AddCodeLine ("lda sreg+1");
4019                     AddCodeLine ("jsr boolge");
4020                     return;
4021
4022                 default:
4023                     typeerror (flags);
4024             }
4025         }
4026
4027
4028         /* If we go here, we didn't emit code. Push the lhs on stack and fall
4029          * into the normal, non-optimized stuff. Note: The standard stuff will
4030          * always work with ints.
4031          */
4032         flags &= ~CF_FORCECHAR;
4033         g_push (flags & ~CF_CONST, 0);
4034     }
4035
4036     /* Use long way over the stack */
4037     oper (flags, val, ops);
4038 }
4039
4040
4041
4042 /*****************************************************************************/
4043 /*                         Allocating static storage                         */
4044 /*****************************************************************************/
4045
4046
4047
4048 void g_res (unsigned n)
4049 /* Reserve static storage, n bytes */
4050 {
4051     AddDataLine ("\t.res\t%u,$00", n);
4052 }
4053
4054
4055
4056 void g_defdata (unsigned flags, unsigned long val, long offs)
4057 /* Define data with the size given in flags */
4058 {
4059     if (flags & CF_CONST) {
4060
4061         /* Numeric constant */
4062         switch (flags & CF_TYPE) {
4063
4064             case CF_CHAR:
4065                 AddDataLine ("\t.byte\t$%02lX", val & 0xFF);
4066                 break;
4067
4068             case CF_INT:
4069                 AddDataLine ("\t.word\t$%04lX", val & 0xFFFF);
4070                 break;
4071
4072             case CF_LONG:
4073                 AddDataLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
4074                 break;
4075
4076             default:
4077                 typeerror (flags);
4078                 break;
4079
4080         }
4081
4082     } else {
4083
4084         /* Create the correct label name */
4085         const char* Label = GetLabelName (flags, val, offs);
4086
4087         /* Labels are always 16 bit */
4088         AddDataLine ("\t.addr\t%s", Label);
4089
4090     }
4091 }
4092
4093
4094
4095 void g_defbytes (const void* Bytes, unsigned Count)
4096 /* Output a row of bytes as a constant */
4097 {
4098     unsigned Chunk;
4099     char Buf [128];
4100     char* B;
4101
4102     /* Cast the buffer pointer */
4103     const unsigned char* Data = (const unsigned char*) Bytes;
4104
4105     /* Output the stuff */
4106     while (Count) {
4107
4108         /* How many go into this line? */
4109         if ((Chunk = Count) > 16) {
4110             Chunk = 16;
4111         }
4112         Count -= Chunk;
4113
4114         /* Output one line */
4115         strcpy (Buf, "\t.byte\t");
4116         B = Buf + 7;
4117         do {
4118             B += sprintf (B, "$%02X", *Data++);
4119             if (--Chunk) {
4120                 *B++ = ',';
4121             }
4122         } while (Chunk);
4123
4124         /* Output the line */
4125         AddDataLine (Buf);
4126     }
4127 }
4128
4129
4130
4131 void g_zerobytes (unsigned Count)
4132 /* Output Count bytes of data initialized with zero */
4133 {
4134     if (Count > 0) {
4135         AddDataLine ("\t.res\t%u,$00", Count);
4136     }
4137 }
4138
4139
4140
4141 void g_initregister (unsigned Label, unsigned Reg, unsigned Size)
4142 /* Initialize a register variable from static initialization data */
4143 {
4144     /* Register variables do always have less than 128 bytes */
4145     unsigned CodeLabel = GetLocalLabel ();
4146     ldxconst (Size-1);
4147     g_defcodelabel (CodeLabel);
4148     AddCodeLine ("lda %s,x", GetLabelName (CF_STATIC, Label, 0));
4149     AddCodeLine ("sta %s,x", GetLabelName (CF_REGVAR, Reg, 0));
4150     AddCodeLine ("dex");
4151     AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4152 }
4153
4154
4155
4156 void g_initauto (unsigned Label, unsigned Size)
4157 /* Initialize a local variable at stack offset zero from static data */
4158 {
4159     unsigned CodeLabel = GetLocalLabel ();
4160
4161     CheckLocalOffs (Size);
4162     if (Size <= 128) {
4163         ldyconst (Size-1);
4164         g_defcodelabel (CodeLabel);
4165         AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, Label, 0));
4166         AddCodeLine ("sta (sp),y");
4167         AddCodeLine ("dey");
4168         AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4169     } else if (Size <= 256) {
4170         ldyconst (0);
4171         g_defcodelabel (CodeLabel);
4172         AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, Label, 0));
4173         AddCodeLine ("sta (sp),y");
4174         AddCodeLine ("iny");
4175         AddCodeLine ("cpy #$%02X", (unsigned char) Size);
4176         AddCodeLine ("bne %s", LocalLabelName (CodeLabel));
4177     }
4178 }
4179
4180
4181
4182 void g_initstatic (unsigned InitLabel, unsigned VarLabel, unsigned Size)
4183 /* Initialize a static local variable from static initialization data */
4184 {
4185     if (Size <= 128) {
4186         unsigned CodeLabel = GetLocalLabel ();
4187         ldyconst (Size-1);
4188         g_defcodelabel (CodeLabel);
4189         AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, InitLabel, 0));
4190         AddCodeLine ("sta %s,y", GetLabelName (CF_STATIC, VarLabel, 0));
4191         AddCodeLine ("dey");
4192         AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4193     } else if (Size <= 256) {
4194         unsigned CodeLabel = GetLocalLabel ();
4195         ldyconst (0);
4196         g_defcodelabel (CodeLabel);
4197         AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, InitLabel, 0));
4198         AddCodeLine ("sta %s,y", GetLabelName (CF_STATIC, VarLabel, 0));
4199         AddCodeLine ("iny");
4200         AddCodeLine ("cpy #$%02X", (unsigned char) Size);
4201         AddCodeLine ("bne %s", LocalLabelName (CodeLabel));
4202     } else {
4203         /* Use the easy way here: memcpy */
4204         g_getimmed (CF_STATIC, VarLabel, 0);
4205         AddCodeLine ("jsr pushax");
4206         g_getimmed (CF_STATIC, InitLabel, 0);
4207         AddCodeLine ("jsr pushax");
4208         g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, Size, 0);
4209         AddCodeLine ("jsr %s", GetLabelName (CF_EXTERNAL, (unsigned long) "memcpy", 0));
4210     }
4211 }
4212
4213
4214
4215 /*****************************************************************************/
4216 /*                             Switch statement                              */
4217 /*****************************************************************************/
4218
4219
4220
4221 void g_switch (Collection* Nodes, unsigned DefaultLabel, unsigned Depth)
4222 /* Generate code for a switch statement */
4223 {
4224     unsigned NextLabel = 0;
4225     unsigned I;
4226
4227     /* Setup registers and determine which compare insn to use */
4228     const char* Compare;
4229     switch (Depth) {
4230         case 1:
4231             Compare = "cmp #$%02X";
4232             break;
4233         case 2:
4234             Compare = "cpx #$%02X";
4235             break;
4236         case 3:
4237             AddCodeLine ("ldy sreg");
4238             Compare = "cpy #$%02X";
4239             break;
4240         case 4:
4241             AddCodeLine ("ldy sreg+1");
4242             Compare = "cpy #$%02X";
4243             break;
4244         default:
4245             Internal ("Invalid depth in g_switch: %u", Depth);
4246     }
4247
4248     /* Walk over all nodes */
4249     for (I = 0; I < CollCount (Nodes); ++I) {
4250
4251         /* Get the next case node */
4252         CaseNode* N = CollAtUnchecked (Nodes, I);
4253
4254         /* If we have a next label, define it */
4255         if (NextLabel) {
4256             g_defcodelabel (NextLabel);
4257             NextLabel = 0;
4258         }
4259
4260         /* Do the compare */
4261         AddCodeLine (Compare, CN_GetValue (N));
4262
4263         /* If this is the last level, jump directly to the case code if found */
4264         if (Depth == 1) {
4265
4266             /* Branch if equal */
4267             g_falsejump (0, CN_GetLabel (N));
4268
4269         } else {
4270
4271             /* Determine the next label */
4272             if (I == CollCount (Nodes) - 1) {
4273                 /* Last node means not found */
4274                 g_truejump (0, DefaultLabel);
4275             } else {
4276                 /* Jump to the next check */
4277                 NextLabel = GetLocalLabel ();
4278                 g_truejump (0, NextLabel);
4279             }
4280
4281             /* Check the next level */
4282             g_switch (N->Nodes, DefaultLabel, Depth-1);
4283
4284         }
4285     }
4286
4287     /* If we go here, we haven't found the label */
4288     g_jump (DefaultLabel);
4289 }
4290
4291
4292
4293 /*****************************************************************************/
4294 /*                       User supplied assembler code                        */
4295 /*****************************************************************************/
4296
4297
4298
4299 void g_asmcode (struct StrBuf* B)
4300 /* Output one line of assembler code. */
4301 {
4302     AddCodeLine ("%.*s", SB_GetLen (B), SB_GetConstBuf (B));
4303 }
4304
4305
4306