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