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