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