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