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