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