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