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