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