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