]> git.sur5r.net Git - cc65/blob - src/cc65/codegen.c
remove TABs
[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 void g_lateadjustSP (unsigned label)
2429 /* Adjust stack based on non-immediate data */
2430 {
2431     AddCodeLine ("pha");
2432     AddCodeLine ("lda %s", LocalLabelName (label));
2433     AddCodeLine ("clc");
2434     AddCodeLine ("adc sp");
2435     AddCodeLine ("sta sp");
2436     AddCodeLine ("lda %s+1", LocalLabelName (label));
2437     AddCodeLine ("adc sp+1");
2438     AddCodeLine ("sta sp+1");
2439     AddCodeLine ("pla");
2440 }
2441
2442 void g_drop (unsigned Space)
2443 /* Drop space allocated on the stack */
2444 {
2445     if (Space > 255) {
2446         /* Inline the code since calling addysp repeatedly is quite some
2447         ** overhead.
2448         */
2449         AddCodeLine ("pha");
2450         AddCodeLine ("lda #$%02X", (unsigned char) Space);
2451         AddCodeLine ("clc");
2452         AddCodeLine ("adc sp");
2453         AddCodeLine ("sta sp");
2454         AddCodeLine ("lda #$%02X", (unsigned char) (Space >> 8));
2455         AddCodeLine ("adc sp+1");
2456         AddCodeLine ("sta sp+1");
2457         AddCodeLine ("pla");
2458     } else if (Space > 8) {
2459         AddCodeLine ("ldy #$%02X", Space);
2460         AddCodeLine ("jsr addysp");
2461     } else if (Space != 0) {
2462         AddCodeLine ("jsr incsp%u", Space);
2463     }
2464 }
2465
2466
2467
2468 void g_space (int Space)
2469 /* Create or drop space on the stack */
2470 {
2471     if (Space < 0) {
2472         /* This is actually a drop operation */
2473         g_drop (-Space);
2474     } else if (Space > 255) {
2475         /* Inline the code since calling subysp repeatedly is quite some
2476         ** overhead.
2477         */
2478         AddCodeLine ("pha");
2479         AddCodeLine ("lda sp");
2480         AddCodeLine ("sec");
2481         AddCodeLine ("sbc #$%02X", (unsigned char) Space);
2482         AddCodeLine ("sta sp");
2483         AddCodeLine ("lda sp+1");
2484         AddCodeLine ("sbc #$%02X", (unsigned char) (Space >> 8));
2485         AddCodeLine ("sta sp+1");
2486         AddCodeLine ("pla");
2487     } else if (Space > 8) {
2488         AddCodeLine ("ldy #$%02X", Space);
2489         AddCodeLine ("jsr subysp");
2490     } else if (Space != 0) {
2491         AddCodeLine ("jsr decsp%u", Space);
2492     }
2493 }
2494
2495
2496
2497 void g_cstackcheck (void)
2498 /* Check for a C stack overflow */
2499 {
2500     AddCodeLine ("jsr cstkchk");
2501 }
2502
2503
2504
2505 void g_stackcheck (void)
2506 /* Check for a stack overflow */
2507 {
2508     AddCodeLine ("jsr stkchk");
2509 }
2510
2511
2512
2513 void g_add (unsigned flags, unsigned long val)
2514 /* Primary = TOS + Primary */
2515 {
2516     static const char* const ops[4] = {
2517         "tosaddax", "tosaddax", "tosaddeax", "tosaddeax"
2518     };
2519
2520     if (flags & CF_CONST) {
2521         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2522         g_push (flags & ~CF_CONST, 0);
2523     }
2524     oper (flags, val, ops);
2525 }
2526
2527
2528
2529 void g_sub (unsigned flags, unsigned long val)
2530 /* Primary = TOS - Primary */
2531 {
2532     static const char* const ops[4] = {
2533         "tossubax", "tossubax", "tossubeax", "tossubeax"
2534     };
2535
2536     if (flags & CF_CONST) {
2537         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2538         g_push (flags & ~CF_CONST, 0);
2539     }
2540     oper (flags, val, ops);
2541 }
2542
2543
2544
2545 void g_rsub (unsigned flags, unsigned long val)
2546 /* Primary = Primary - TOS */
2547 {
2548     static const char* const ops[4] = {
2549         "tosrsubax", "tosrsubax", "tosrsubeax", "tosrsubeax"
2550     };
2551     oper (flags, val, ops);
2552 }
2553
2554
2555
2556 void g_mul (unsigned flags, unsigned long val)
2557 /* Primary = TOS * Primary */
2558 {
2559     static const char* const ops[4] = {
2560         "tosmulax", "tosumulax", "tosmuleax", "tosumuleax"
2561     };
2562
2563     int p2;
2564
2565     /* Do strength reduction if the value is constant and a power of two */
2566     if (flags & CF_CONST && (p2 = PowerOf2 (val)) >= 0) {
2567         /* Generate a shift instead */
2568         g_asl (flags, p2);
2569         return;
2570     }
2571
2572     /* If the right hand side is const, the lhs is not on stack but still
2573     ** in the primary register.
2574     */
2575     if (flags & CF_CONST) {
2576
2577         switch (flags & CF_TYPEMASK) {
2578
2579             case CF_CHAR:
2580                 if (flags & CF_FORCECHAR) {
2581                     /* Handle some special cases */
2582                     switch (val) {
2583
2584                         case 3:
2585                             AddCodeLine ("sta tmp1");
2586                             AddCodeLine ("asl a");
2587                             AddCodeLine ("clc");
2588                             AddCodeLine ("adc tmp1");
2589                             return;
2590
2591                         case 5:
2592                             AddCodeLine ("sta tmp1");
2593                             AddCodeLine ("asl a");
2594                             AddCodeLine ("asl a");
2595                             AddCodeLine ("clc");
2596                             AddCodeLine ("adc tmp1");
2597                             return;
2598
2599                         case 6:
2600                             AddCodeLine ("sta tmp1");
2601                             AddCodeLine ("asl a");
2602                             AddCodeLine ("clc");
2603                             AddCodeLine ("adc tmp1");
2604                             AddCodeLine ("asl a");
2605                             return;
2606
2607                         case 10:
2608                             AddCodeLine ("sta tmp1");
2609                             AddCodeLine ("asl a");
2610                             AddCodeLine ("asl a");
2611                             AddCodeLine ("clc");
2612                             AddCodeLine ("adc tmp1");
2613                             AddCodeLine ("asl a");
2614                             return;
2615                     }
2616                 }
2617                 /* FALLTHROUGH */
2618
2619             case CF_INT:
2620                 switch (val) {
2621                     case 3:
2622                         AddCodeLine ("jsr mulax3");
2623                         return;
2624                     case 5:
2625                         AddCodeLine ("jsr mulax5");
2626                         return;
2627                     case 6:
2628                         AddCodeLine ("jsr mulax6");
2629                         return;
2630                     case 7:
2631                         AddCodeLine ("jsr mulax7");
2632                         return;
2633                     case 9:
2634                         AddCodeLine ("jsr mulax9");
2635                         return;
2636                     case 10:
2637                         AddCodeLine ("jsr mulax10");
2638                         return;
2639                 }
2640                 break;
2641
2642             case CF_LONG:
2643                 break;
2644
2645             default:
2646                 typeerror (flags);
2647         }
2648
2649         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2650         ** into the normal, non-optimized stuff.
2651         */
2652         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2653         g_push (flags & ~CF_CONST, 0);
2654
2655     }
2656
2657     /* Use long way over the stack */
2658     oper (flags, val, ops);
2659 }
2660
2661
2662
2663 void g_div (unsigned flags, unsigned long val)
2664 /* Primary = TOS / Primary */
2665 {
2666     static const char* const ops[4] = {
2667         "tosdivax", "tosudivax", "tosdiveax", "tosudiveax"
2668     };
2669
2670     /* Do strength reduction if the value is constant and a power of two */
2671     int p2;
2672     if ((flags & CF_CONST) && (p2 = PowerOf2 (val)) >= 0) {
2673         /* Generate a shift instead */
2674         g_asr (flags, p2);
2675     } else {
2676         /* Generate a division */
2677         if (flags & CF_CONST) {
2678             /* lhs is not on stack */
2679             flags &= ~CF_FORCECHAR;     /* Handle chars as ints */
2680             g_push (flags & ~CF_CONST, 0);
2681         }
2682         oper (flags, val, ops);
2683     }
2684 }
2685
2686
2687
2688 void g_mod (unsigned flags, unsigned long val)
2689 /* Primary = TOS % Primary */
2690 {
2691     static const char* const ops[4] = {
2692         "tosmodax", "tosumodax", "tosmodeax", "tosumodeax"
2693     };
2694     int p2;
2695
2696     /* Check if we can do some cost reduction */
2697     if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = PowerOf2 (val)) >= 0) {
2698         /* We can do that with an AND operation */
2699         g_and (flags, val - 1);
2700     } else {
2701         /* Do it the hard way... */
2702         if (flags & CF_CONST) {
2703             /* lhs is not on stack */
2704             flags &= ~CF_FORCECHAR;     /* Handle chars as ints */
2705             g_push (flags & ~CF_CONST, 0);
2706         }
2707         oper (flags, val, ops);
2708     }
2709 }
2710
2711
2712
2713 void g_or (unsigned flags, unsigned long val)
2714 /* Primary = TOS | Primary */
2715 {
2716     static const char* const ops[4] = {
2717         "tosorax", "tosorax", "tosoreax", "tosoreax"
2718     };
2719
2720     /* If the right hand side is const, the lhs is not on stack but still
2721     ** in the primary register.
2722     */
2723     if (flags & CF_CONST) {
2724
2725         switch (flags & CF_TYPEMASK) {
2726
2727             case CF_CHAR:
2728                 if (flags & CF_FORCECHAR) {
2729                     if ((val & 0xFF) != 0) {
2730                         AddCodeLine ("ora #$%02X", (unsigned char)val);
2731                     }
2732                     return;
2733                 }
2734                 /* FALLTHROUGH */
2735
2736             case CF_INT:
2737                 if (val <= 0xFF) {
2738                     if ((val & 0xFF) != 0) {
2739                         AddCodeLine ("ora #$%02X", (unsigned char)val);
2740                     }
2741                 } else if ((val & 0xFF00) == 0xFF00) {
2742                     if ((val & 0xFF) != 0) {
2743                         AddCodeLine ("ora #$%02X", (unsigned char)val);
2744                     }
2745                     AddCodeLine ("ldx #$FF");
2746                 } else if (val != 0) {
2747                     AddCodeLine ("ora #$%02X", (unsigned char)val);
2748                     AddCodeLine ("pha");
2749                     AddCodeLine ("txa");
2750                     AddCodeLine ("ora #$%02X", (unsigned char)(val >> 8));
2751                     AddCodeLine ("tax");
2752                     AddCodeLine ("pla");
2753                 }
2754                 return;
2755
2756             case CF_LONG:
2757                 if (val <= 0xFF) {
2758                     if ((val & 0xFF) != 0) {
2759                         AddCodeLine ("ora #$%02X", (unsigned char)val);
2760                     }
2761                     return;
2762                 }
2763                 break;
2764
2765             default:
2766                 typeerror (flags);
2767         }
2768
2769         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2770         ** into the normal, non-optimized stuff. Note: The standard stuff will
2771         ** always work with ints.
2772         */
2773         flags &= ~CF_FORCECHAR;
2774         g_push (flags & ~CF_CONST, 0);
2775     }
2776
2777     /* Use long way over the stack */
2778     oper (flags, val, ops);
2779 }
2780
2781
2782
2783 void g_xor (unsigned flags, unsigned long val)
2784 /* Primary = TOS ^ Primary */
2785 {
2786     static const char* const ops[4] = {
2787         "tosxorax", "tosxorax", "tosxoreax", "tosxoreax"
2788     };
2789
2790
2791     /* If the right hand side is const, the lhs is not on stack but still
2792     ** in the primary register.
2793     */
2794     if (flags & CF_CONST) {
2795
2796         switch (flags & CF_TYPEMASK) {
2797
2798             case CF_CHAR:
2799                 if (flags & CF_FORCECHAR) {
2800                     if ((val & 0xFF) != 0) {
2801                         AddCodeLine ("eor #$%02X", (unsigned char)val);
2802                     }
2803                     return;
2804                 }
2805                 /* FALLTHROUGH */
2806
2807             case CF_INT:
2808                 if (val <= 0xFF) {
2809                     if (val != 0) {
2810                         AddCodeLine ("eor #$%02X", (unsigned char)val);
2811                     }
2812                 } else if (val != 0) {
2813                     if ((val & 0xFF) != 0) {
2814                         AddCodeLine ("eor #$%02X", (unsigned char)val);
2815                     }
2816                     AddCodeLine ("pha");
2817                     AddCodeLine ("txa");
2818                     AddCodeLine ("eor #$%02X", (unsigned char)(val >> 8));
2819                     AddCodeLine ("tax");
2820                     AddCodeLine ("pla");
2821                 }
2822                 return;
2823
2824             case CF_LONG:
2825                 if (val <= 0xFF) {
2826                     if (val != 0) {
2827                         AddCodeLine ("eor #$%02X", (unsigned char)val);
2828                     }
2829                     return;
2830                 }
2831                 break;
2832
2833             default:
2834                 typeerror (flags);
2835         }
2836
2837         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2838         ** into the normal, non-optimized stuff. Note: The standard stuff will
2839         ** always work with ints.
2840         */
2841         flags &= ~CF_FORCECHAR;
2842         g_push (flags & ~CF_CONST, 0);
2843     }
2844
2845     /* Use long way over the stack */
2846     oper (flags, val, ops);
2847 }
2848
2849
2850
2851 void g_and (unsigned Flags, unsigned long Val)
2852 /* Primary = TOS & Primary */
2853 {
2854     static const char* const ops[4] = {
2855         "tosandax", "tosandax", "tosandeax", "tosandeax"
2856     };
2857
2858     /* If the right hand side is const, the lhs is not on stack but still
2859     ** in the primary register.
2860     */
2861     if (Flags & CF_CONST) {
2862
2863         switch (Flags & CF_TYPEMASK) {
2864
2865             case CF_CHAR:
2866                 if (Flags & CF_FORCECHAR) {
2867                     if ((Val & 0xFF) == 0x00) {
2868                         AddCodeLine ("lda #$00");
2869                     } else if ((Val & 0xFF) != 0xFF) {
2870                         AddCodeLine ("and #$%02X", (unsigned char)Val);
2871                     }
2872                     return;
2873                 }
2874                 /* FALLTHROUGH */
2875             case CF_INT:
2876                 if ((Val & 0xFFFF) != 0xFFFF) {
2877                     if (Val <= 0xFF) {
2878                         AddCodeLine ("ldx #$00");
2879                         if (Val == 0) {
2880                             AddCodeLine ("lda #$00");
2881                         } else if (Val != 0xFF) {
2882                             AddCodeLine ("and #$%02X", (unsigned char)Val);
2883                         }
2884                     } else if ((Val & 0xFFFF) == 0xFF00) {
2885                         AddCodeLine ("lda #$00");
2886                     } else if ((Val & 0xFF00) == 0xFF00) {
2887                         AddCodeLine ("and #$%02X", (unsigned char)Val);
2888                     } else if ((Val & 0x00FF) == 0x0000) {
2889                         AddCodeLine ("txa");
2890                         AddCodeLine ("and #$%02X", (unsigned char)(Val >> 8));
2891                         AddCodeLine ("tax");
2892                         AddCodeLine ("lda #$00");
2893                     } else {
2894                         AddCodeLine ("tay");
2895                         AddCodeLine ("txa");
2896                         AddCodeLine ("and #$%02X", (unsigned char)(Val >> 8));
2897                         AddCodeLine ("tax");
2898                         AddCodeLine ("tya");
2899                         if ((Val & 0x00FF) == 0x0000) {
2900                             AddCodeLine ("lda #$00");
2901                         } else if ((Val & 0x00FF) != 0x00FF) {
2902                             AddCodeLine ("and #$%02X", (unsigned char)Val);
2903                         }
2904                     }
2905                 }
2906                 return;
2907
2908             case CF_LONG:
2909                 if (Val <= 0xFF) {
2910                     AddCodeLine ("ldx #$00");
2911                     AddCodeLine ("stx sreg+1");
2912                     AddCodeLine ("stx sreg");
2913                     if ((Val & 0xFF) != 0xFF) {
2914                          AddCodeLine ("and #$%02X", (unsigned char)Val);
2915                     }
2916                     return;
2917                 } else if (Val == 0xFF00) {
2918                     AddCodeLine ("lda #$00");
2919                     AddCodeLine ("sta sreg+1");
2920                     AddCodeLine ("sta sreg");
2921                     return;
2922                 }
2923                 break;
2924
2925             default:
2926                 typeerror (Flags);
2927         }
2928
2929         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2930         ** into the normal, non-optimized stuff. Note: The standard stuff will
2931         ** always work with ints.
2932         */
2933         Flags &= ~CF_FORCECHAR;
2934         g_push (Flags & ~CF_CONST, 0);
2935     }
2936
2937     /* Use long way over the stack */
2938     oper (Flags, Val, ops);
2939 }
2940
2941
2942
2943 void g_asr (unsigned flags, unsigned long val)
2944 /* Primary = TOS >> Primary */
2945 {
2946     static const char* const ops[4] = {
2947         "tosasrax", "tosshrax", "tosasreax", "tosshreax"
2948     };
2949
2950     /* If the right hand side is const, the lhs is not on stack but still
2951     ** in the primary register.
2952     */
2953     if (flags & CF_CONST) {
2954
2955         switch (flags & CF_TYPEMASK) {
2956
2957             case CF_CHAR:
2958             case CF_INT:
2959                 val &= 0x0F;
2960                 if (val >= 8) {
2961                     if (flags & CF_UNSIGNED) {
2962                         AddCodeLine ("txa");
2963                         AddCodeLine ("ldx #$00");
2964                     } else {
2965                         unsigned L = GetLocalLabel();
2966                         AddCodeLine ("cpx #$80");   /* Sign bit into carry */
2967                         AddCodeLine ("txa");
2968                         AddCodeLine ("ldx #$00");
2969                         AddCodeLine ("bcc %s", LocalLabelName (L));
2970                         AddCodeLine ("dex");        /* Make $FF */
2971                         g_defcodelabel (L);
2972                     }
2973                     val -= 8;
2974                 }
2975                 if (val >= 4) {
2976                     if (flags & CF_UNSIGNED) {
2977                         AddCodeLine ("jsr shrax4");
2978                     } else {
2979                         AddCodeLine ("jsr asrax4");
2980                     }
2981                     val -= 4;
2982                 }
2983                 if (val > 0) {
2984                     if (flags & CF_UNSIGNED) {
2985                         AddCodeLine ("jsr shrax%ld", val);
2986                     } else {
2987                         AddCodeLine ("jsr asrax%ld", val);
2988                     }
2989                 }
2990                 return;
2991
2992             case CF_LONG:
2993                 val &= 0x1F;
2994                 if (val >= 24) {
2995                     AddCodeLine ("ldx #$00");
2996                     AddCodeLine ("lda sreg+1");
2997                     if ((flags & CF_UNSIGNED) == 0) {
2998                         unsigned L = GetLocalLabel();
2999                         AddCodeLine ("bpl %s", LocalLabelName (L));
3000                         AddCodeLine ("dex");
3001                         g_defcodelabel (L);
3002                     }
3003                     AddCodeLine ("stx sreg");
3004                     AddCodeLine ("stx sreg+1");
3005                     val -= 24;
3006                 }
3007                 if (val >= 16) {
3008                     AddCodeLine ("ldy #$00");
3009                     AddCodeLine ("ldx sreg+1");
3010                     if ((flags & CF_UNSIGNED) == 0) {
3011                         unsigned L = GetLocalLabel();
3012                         AddCodeLine ("bpl %s", LocalLabelName (L));
3013                         AddCodeLine ("dey");
3014                         g_defcodelabel (L);
3015                     }
3016                     AddCodeLine ("lda sreg");
3017                     AddCodeLine ("sty sreg+1");
3018                     AddCodeLine ("sty sreg");
3019                     val -= 16;
3020                 }
3021                 if (val >= 8) {
3022                     AddCodeLine ("txa");
3023                     AddCodeLine ("ldx sreg");
3024                     AddCodeLine ("ldy sreg+1");
3025                     AddCodeLine ("sty sreg");
3026                     if ((flags & CF_UNSIGNED) == 0) {
3027                         unsigned L = GetLocalLabel();
3028                         AddCodeLine ("cpy #$80");
3029                         AddCodeLine ("ldy #$00");
3030                         AddCodeLine ("bcc %s", LocalLabelName (L));
3031                         AddCodeLine ("dey");
3032                         g_defcodelabel (L);
3033                     } else {
3034                         AddCodeLine ("ldy #$00");
3035                     }
3036                     AddCodeLine ("sty sreg+1");
3037                     val -= 8;
3038                 }
3039                 if (val >= 4) {
3040                     if (flags & CF_UNSIGNED) {
3041                         AddCodeLine ("jsr shreax4");
3042                     } else {
3043                         AddCodeLine ("jsr asreax4");
3044                     }
3045                     val -= 4;
3046                 }
3047                 if (val > 0) {
3048                     if (flags & CF_UNSIGNED) {
3049                         AddCodeLine ("jsr shreax%ld", val);
3050                     } else {
3051                         AddCodeLine ("jsr asreax%ld", val);
3052                     }
3053                 }
3054                 return;
3055
3056             default:
3057                 typeerror (flags);
3058         }
3059
3060         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3061         ** into the normal, non-optimized stuff. Note: The standard stuff will
3062         ** always work with ints.
3063         */
3064         flags &= ~CF_FORCECHAR;
3065         g_push (flags & ~CF_CONST, 0);
3066     }
3067
3068     /* Use long way over the stack */
3069     oper (flags, val, ops);
3070 }
3071
3072
3073
3074 void g_asl (unsigned flags, unsigned long val)
3075 /* Primary = TOS << Primary */
3076 {
3077     static const char* const ops[4] = {
3078         "tosaslax", "tosshlax", "tosasleax", "tosshleax"
3079     };
3080
3081
3082     /* If the right hand side is const, the lhs is not on stack but still
3083     ** in the primary register.
3084     */
3085     if (flags & CF_CONST) {
3086
3087         switch (flags & CF_TYPEMASK) {
3088
3089             case CF_CHAR:
3090             case CF_INT:
3091                 val &= 0x0F;
3092                 if (val >= 8) {
3093                     AddCodeLine ("tax");
3094                     AddCodeLine ("lda #$00");
3095                     val -= 8;
3096                 }
3097                 if (val >= 4) {
3098                     if (flags & CF_UNSIGNED) {
3099                         AddCodeLine ("jsr shlax4");
3100                     } else {
3101                         AddCodeLine ("jsr aslax4");
3102                     }
3103                     val -= 4;
3104                 }
3105                 if (val > 0) {
3106                     if (flags & CF_UNSIGNED) {
3107                         AddCodeLine ("jsr shlax%ld", val);
3108                     } else {
3109                         AddCodeLine ("jsr aslax%ld", val);
3110                     }
3111                 }
3112                 return;
3113
3114             case CF_LONG:
3115                 val &= 0x1F;
3116                 if (val >= 24) {
3117                     AddCodeLine ("sta sreg+1");
3118                     AddCodeLine ("lda #$00");
3119                     AddCodeLine ("tax");
3120                     AddCodeLine ("sta sreg");
3121                     val -= 24;
3122                 }
3123                 if (val >= 16) {
3124                     AddCodeLine ("stx sreg+1");
3125                     AddCodeLine ("sta sreg");
3126                     AddCodeLine ("lda #$00");
3127                     AddCodeLine ("tax");
3128                     val -= 16;
3129                 }
3130                 if (val >= 8) {
3131                     AddCodeLine ("ldy sreg");
3132                     AddCodeLine ("sty sreg+1");
3133                     AddCodeLine ("stx sreg");
3134                     AddCodeLine ("tax");
3135                     AddCodeLine ("lda #$00");
3136                     val -= 8;
3137                 }
3138                 if (val > 4) {
3139                     if (flags & CF_UNSIGNED) {
3140                         AddCodeLine ("jsr shleax4");
3141                     } else {
3142                         AddCodeLine ("jsr asleax4");
3143                     }
3144                     val -= 4;
3145                 }
3146                 if (val > 0) {
3147                     if (flags & CF_UNSIGNED) {
3148                         AddCodeLine ("jsr shleax%ld", val);
3149                     } else {
3150                         AddCodeLine ("jsr asleax%ld", val);
3151                     }
3152                 }
3153                 return;
3154
3155             default:
3156                 typeerror (flags);
3157         }
3158
3159         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3160         ** into the normal, non-optimized stuff. Note: The standard stuff will
3161         ** always work with ints.
3162         */
3163         flags &= ~CF_FORCECHAR;
3164         g_push (flags & ~CF_CONST, 0);
3165     }
3166
3167     /* Use long way over the stack */
3168     oper (flags, val, ops);
3169 }
3170
3171
3172
3173 void g_neg (unsigned Flags)
3174 /* Primary = -Primary */
3175 {
3176     switch (Flags & CF_TYPEMASK) {
3177
3178         case CF_CHAR:
3179             if (Flags & CF_FORCECHAR) {
3180                 AddCodeLine ("eor #$FF");
3181                 AddCodeLine ("clc");
3182                 AddCodeLine ("adc #$01");
3183                 return;
3184             }
3185             /* FALLTHROUGH */
3186
3187         case CF_INT:
3188             AddCodeLine ("jsr negax");
3189             break;
3190
3191         case CF_LONG:
3192             AddCodeLine ("jsr negeax");
3193             break;
3194
3195         default:
3196             typeerror (Flags);
3197     }
3198 }
3199
3200
3201
3202 void g_bneg (unsigned flags)
3203 /* Primary = !Primary */
3204 {
3205     switch (flags & CF_TYPEMASK) {
3206
3207         case CF_CHAR:
3208             AddCodeLine ("jsr bnega");
3209             break;
3210
3211         case CF_INT:
3212             AddCodeLine ("jsr bnegax");
3213             break;
3214
3215         case CF_LONG:
3216             AddCodeLine ("jsr bnegeax");
3217             break;
3218
3219         default:
3220             typeerror (flags);
3221     }
3222 }
3223
3224
3225
3226 void g_com (unsigned Flags)
3227 /* Primary = ~Primary */
3228 {
3229     switch (Flags & CF_TYPEMASK) {
3230
3231         case CF_CHAR:
3232             if (Flags & CF_FORCECHAR) {
3233                 AddCodeLine ("eor #$FF");
3234                 return;
3235             }
3236             /* FALLTHROUGH */
3237
3238         case CF_INT:
3239             AddCodeLine ("jsr complax");
3240             break;
3241
3242         case CF_LONG:
3243             AddCodeLine ("jsr compleax");
3244             break;
3245
3246         default:
3247             typeerror (Flags);
3248     }
3249 }
3250
3251
3252
3253 void g_inc (unsigned flags, unsigned long val)
3254 /* Increment the primary register by a given number */
3255 {
3256     /* Don't inc by zero */
3257     if (val == 0) {
3258         return;
3259     }
3260
3261     /* Generate code for the supported types */
3262     flags &= ~CF_CONST;
3263     switch (flags & CF_TYPEMASK) {
3264
3265         case CF_CHAR:
3266             if (flags & CF_FORCECHAR) {
3267                 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val <= 2) {
3268                     while (val--) {
3269                         AddCodeLine ("ina");
3270                     }
3271                 } else {
3272                     AddCodeLine ("clc");
3273                     AddCodeLine ("adc #$%02X", (unsigned char)val);
3274                 }
3275                 break;
3276             }
3277             /* FALLTHROUGH */
3278
3279         case CF_INT:
3280             if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val == 1) {
3281                 unsigned L = GetLocalLabel();
3282                 AddCodeLine ("ina");
3283                 AddCodeLine ("bne %s", LocalLabelName (L));
3284                 AddCodeLine ("inx");
3285                 g_defcodelabel (L);
3286             } else if (IS_Get (&CodeSizeFactor) < 200) {
3287                 /* Use jsr calls */
3288                 if (val <= 8) {
3289                     AddCodeLine ("jsr incax%lu", val);
3290                 } else if (val <= 255) {
3291                     AddCodeLine ("ldy #$%02X", (unsigned char) val);
3292                     AddCodeLine ("jsr incaxy");
3293                 } else {
3294                     g_add (flags | CF_CONST, val);
3295                 }
3296             } else {
3297                 /* Inline the code */
3298                 if (val <= 0x300) {
3299                     if ((val & 0xFF) != 0) {
3300                         unsigned L = GetLocalLabel();
3301                         AddCodeLine ("clc");
3302                         AddCodeLine ("adc #$%02X", (unsigned char) val);
3303                         AddCodeLine ("bcc %s", LocalLabelName (L));
3304                         AddCodeLine ("inx");
3305                         g_defcodelabel (L);
3306                     }
3307                     if (val >= 0x100) {
3308                         AddCodeLine ("inx");
3309                     }
3310                     if (val >= 0x200) {
3311                         AddCodeLine ("inx");
3312                     }
3313                     if (val >= 0x300) {
3314                         AddCodeLine ("inx");
3315                     }
3316                 } else if ((val & 0xFF) != 0) {
3317                     AddCodeLine ("clc");
3318                     AddCodeLine ("adc #$%02X", (unsigned char) val);
3319                     AddCodeLine ("pha");
3320                     AddCodeLine ("txa");
3321                     AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3322                     AddCodeLine ("tax");
3323                     AddCodeLine ("pla");
3324                 } else {
3325                     AddCodeLine ("pha");
3326                     AddCodeLine ("txa");
3327                     AddCodeLine ("clc");
3328                     AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3329                     AddCodeLine ("tax");
3330                     AddCodeLine ("pla");
3331                 }
3332             }
3333             break;
3334
3335         case CF_LONG:
3336             if (val <= 255) {
3337                 AddCodeLine ("ldy #$%02X", (unsigned char) val);
3338                 AddCodeLine ("jsr inceaxy");
3339             } else {
3340                 g_add (flags | CF_CONST, val);
3341             }
3342             break;
3343
3344         default:
3345             typeerror (flags);
3346
3347     }
3348 }
3349
3350
3351
3352 void g_dec (unsigned flags, unsigned long val)
3353 /* Decrement the primary register by a given number */
3354 {
3355     /* Don't dec by zero */
3356     if (val == 0) {
3357         return;
3358     }
3359
3360     /* Generate code for the supported types */
3361     flags &= ~CF_CONST;
3362     switch (flags & CF_TYPEMASK) {
3363
3364         case CF_CHAR:
3365             if (flags & CF_FORCECHAR) {
3366                 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val <= 2) {
3367                     while (val--) {
3368                         AddCodeLine ("dea");
3369                     }
3370                 } else {
3371                     AddCodeLine ("sec");
3372                     AddCodeLine ("sbc #$%02X", (unsigned char)val);
3373                 }
3374                 break;
3375             }
3376             /* FALLTHROUGH */
3377
3378         case CF_INT:
3379             if (IS_Get (&CodeSizeFactor) < 200) {
3380                 /* Use subroutines */
3381                 if (val <= 8) {
3382                     AddCodeLine ("jsr decax%d", (int) val);
3383                 } else if (val <= 255) {
3384                     AddCodeLine ("ldy #$%02X", (unsigned char) val);
3385                     AddCodeLine ("jsr decaxy");
3386                 } else {
3387                     g_sub (flags | CF_CONST, val);
3388                 }
3389             } else {
3390                 /* Inline the code */
3391                 if (val < 0x300) {
3392                     if ((val & 0xFF) != 0) {
3393                         unsigned L = GetLocalLabel();
3394                         AddCodeLine ("sec");
3395                         AddCodeLine ("sbc #$%02X", (unsigned char) val);
3396                         AddCodeLine ("bcs %s", LocalLabelName (L));
3397                         AddCodeLine ("dex");
3398                         g_defcodelabel (L);
3399                     }
3400                     if (val >= 0x100) {
3401                         AddCodeLine ("dex");
3402                     }
3403                     if (val >= 0x200) {
3404                         AddCodeLine ("dex");
3405                     }
3406                 } else {
3407                     if ((val & 0xFF) != 0) {
3408                         AddCodeLine ("sec");
3409                         AddCodeLine ("sbc #$%02X", (unsigned char) val);
3410                         AddCodeLine ("pha");
3411                         AddCodeLine ("txa");
3412                         AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3413                         AddCodeLine ("tax");
3414                         AddCodeLine ("pla");
3415                     } else {
3416                         AddCodeLine ("pha");
3417                         AddCodeLine ("txa");
3418                         AddCodeLine ("sec");
3419                         AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3420                         AddCodeLine ("tax");
3421                         AddCodeLine ("pla");
3422                     }
3423                 }
3424             }
3425             break;
3426
3427         case CF_LONG:
3428             if (val <= 255) {
3429                 AddCodeLine ("ldy #$%02X", (unsigned char) val);
3430                 AddCodeLine ("jsr deceaxy");
3431             } else {
3432                 g_sub (flags | CF_CONST, val);
3433             }
3434             break;
3435
3436         default:
3437             typeerror (flags);
3438
3439     }
3440 }
3441
3442
3443
3444 /*
3445 ** Following are the conditional operators. They compare the TOS against
3446 ** the primary and put a literal 1 in the primary if the condition is
3447 ** true, otherwise they clear the primary register
3448 */
3449
3450
3451
3452 void g_eq (unsigned flags, unsigned long val)
3453 /* Test for equal */
3454 {
3455     static const char* const ops[4] = {
3456         "toseqax", "toseqax", "toseqeax", "toseqeax"
3457     };
3458
3459     unsigned L;
3460
3461     /* If the right hand side is const, the lhs is not on stack but still
3462     ** in the primary register.
3463     */
3464     if (flags & CF_CONST) {
3465
3466         switch (flags & CF_TYPEMASK) {
3467
3468             case CF_CHAR:
3469                 if (flags & CF_FORCECHAR) {
3470                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3471                     AddCodeLine ("jsr booleq");
3472                     return;
3473                 }
3474                 /* FALLTHROUGH */
3475
3476             case CF_INT:
3477                 L = GetLocalLabel();
3478                 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3479                 AddCodeLine ("bne %s", LocalLabelName (L));
3480                 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3481                 g_defcodelabel (L);
3482                 AddCodeLine ("jsr booleq");
3483                 return;
3484
3485             case CF_LONG:
3486                 break;
3487
3488             default:
3489                 typeerror (flags);
3490         }
3491
3492         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3493         ** into the normal, non-optimized stuff. Note: The standard stuff will
3494         ** always work with ints.
3495         */
3496         flags &= ~CF_FORCECHAR;
3497         g_push (flags & ~CF_CONST, 0);
3498     }
3499
3500     /* Use long way over the stack */
3501     oper (flags, val, ops);
3502 }
3503
3504
3505
3506 void g_ne (unsigned flags, unsigned long val)
3507 /* Test for not equal */
3508 {
3509     static const char* const ops[4] = {
3510         "tosneax", "tosneax", "tosneeax", "tosneeax"
3511     };
3512
3513     unsigned L;
3514
3515     /* If the right hand side is const, the lhs is not on stack but still
3516     ** in the primary register.
3517     */
3518     if (flags & CF_CONST) {
3519
3520         switch (flags & CF_TYPEMASK) {
3521
3522             case CF_CHAR:
3523                 if (flags & CF_FORCECHAR) {
3524                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3525                     AddCodeLine ("jsr boolne");
3526                     return;
3527                 }
3528                 /* FALLTHROUGH */
3529
3530             case CF_INT:
3531                 L = GetLocalLabel();
3532                 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3533                 AddCodeLine ("bne %s", LocalLabelName (L));
3534                 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3535                 g_defcodelabel (L);
3536                 AddCodeLine ("jsr boolne");
3537                 return;
3538
3539             case CF_LONG:
3540                 break;
3541
3542             default:
3543                 typeerror (flags);
3544         }
3545
3546         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3547         ** into the normal, non-optimized stuff. Note: The standard stuff will
3548         ** always work with ints.
3549         */
3550         flags &= ~CF_FORCECHAR;
3551         g_push (flags & ~CF_CONST, 0);
3552     }
3553
3554     /* Use long way over the stack */
3555     oper (flags, val, ops);
3556 }
3557
3558
3559
3560 void g_lt (unsigned flags, unsigned long val)
3561 /* Test for less than */
3562 {
3563     static const char* const ops[4] = {
3564         "tosltax", "tosultax", "toslteax", "tosulteax"
3565     };
3566
3567     unsigned Label;
3568
3569     /* If the right hand side is const, the lhs is not on stack but still
3570     ** in the primary register.
3571     */
3572     if (flags & CF_CONST) {
3573
3574         /* Because the handling of the overflow flag is too complex for
3575         ** inlining, we can handle only unsigned compares, and signed
3576         ** compares against zero here.
3577         */
3578         if (flags & CF_UNSIGNED) {
3579
3580             /* Give a warning in some special cases */
3581             if (val == 0) {
3582                 Warning ("Condition is never true");
3583                 AddCodeLine ("jsr return0");
3584                 return;
3585             }
3586
3587             /* Look at the type */
3588             switch (flags & CF_TYPEMASK) {
3589
3590                 case CF_CHAR:
3591                     if (flags & CF_FORCECHAR) {
3592                         AddCodeLine ("cmp #$%02X", (unsigned char)val);
3593                         AddCodeLine ("jsr boolult");
3594                         return;
3595                     }
3596                     /* FALLTHROUGH */
3597
3598                 case CF_INT:
3599                     /* If the low byte is zero, we must only test the high byte */
3600                     AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3601                     if ((val & 0xFF) != 0) {
3602                         unsigned L = GetLocalLabel();
3603                         AddCodeLine ("bne %s", LocalLabelName (L));
3604                         AddCodeLine ("cmp #$%02X", (unsigned char)val);
3605                         g_defcodelabel (L);
3606                     }
3607                     AddCodeLine ("jsr boolult");
3608                     return;
3609
3610                 case CF_LONG:
3611                     /* Do a subtraction */
3612                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3613                     AddCodeLine ("txa");
3614                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
3615                     AddCodeLine ("lda sreg");
3616                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 16));
3617                     AddCodeLine ("lda sreg+1");
3618                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 24));
3619                     AddCodeLine ("jsr boolult");
3620                     return;
3621
3622                 default:
3623                     typeerror (flags);
3624             }
3625
3626         } else if (val == 0) {
3627
3628             /* A signed compare against zero must only look at the sign bit */
3629             switch (flags & CF_TYPEMASK) {
3630
3631                 case CF_CHAR:
3632                     if (flags & CF_FORCECHAR) {
3633                         AddCodeLine ("asl a");          /* Bit 7 -> carry */
3634                         AddCodeLine ("lda #$00");
3635                         AddCodeLine ("ldx #$00");
3636                         AddCodeLine ("rol a");
3637                         return;
3638                     }
3639                     /* FALLTHROUGH */
3640
3641                 case CF_INT:
3642                     /* Just check the high byte */
3643                     AddCodeLine ("cpx #$80");           /* Bit 7 -> carry */
3644                     AddCodeLine ("lda #$00");
3645                     AddCodeLine ("ldx #$00");
3646                     AddCodeLine ("rol a");
3647                     return;
3648
3649                 case CF_LONG:
3650                     /* Just check the high byte */
3651                     AddCodeLine ("lda sreg+1");
3652                     AddCodeLine ("asl a");              /* Bit 7 -> carry */
3653                     AddCodeLine ("lda #$00");
3654                     AddCodeLine ("ldx #$00");
3655                     AddCodeLine ("rol a");
3656                     return;
3657
3658                 default:
3659                     typeerror (flags);
3660             }
3661
3662         } else {
3663
3664             /* Signed compare against a constant != zero */
3665             switch (flags & CF_TYPEMASK) {
3666
3667                 case CF_CHAR:
3668                     if (flags & CF_FORCECHAR) {
3669                         Label = GetLocalLabel ();
3670                         AddCodeLine ("sec");
3671                         AddCodeLine ("sbc #$%02X", (unsigned char)val);
3672                         AddCodeLine ("bvc %s", LocalLabelName (Label));
3673                         AddCodeLine ("eor #$80");
3674                         g_defcodelabel (Label);
3675                         AddCodeLine ("asl a");          /* Bit 7 -> carry */
3676                         AddCodeLine ("lda #$00");
3677                         AddCodeLine ("ldx #$00");
3678                         AddCodeLine ("rol a");
3679                         return;
3680                     }
3681                     /* FALLTHROUGH */
3682
3683                 case CF_INT:
3684                     /* Do a subtraction */
3685                     Label = GetLocalLabel ();
3686                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
3687                     AddCodeLine ("txa");
3688                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
3689                     AddCodeLine ("bvc %s", LocalLabelName (Label));
3690                     AddCodeLine ("eor #$80");
3691                     g_defcodelabel (Label);
3692                     AddCodeLine ("asl a");          /* Bit 7 -> carry */
3693                     AddCodeLine ("lda #$00");
3694                     AddCodeLine ("ldx #$00");
3695                     AddCodeLine ("rol a");
3696                     return;
3697
3698                 case CF_LONG:
3699                     /* This one is too costly */
3700                     break;
3701
3702                 default:
3703                     typeerror (flags);
3704             }
3705
3706         }
3707
3708         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3709         ** into the normal, non-optimized stuff. Note: The standard stuff will
3710         ** always work with ints.
3711         */
3712         flags &= ~CF_FORCECHAR;
3713         g_push (flags & ~CF_CONST, 0);
3714     }
3715
3716     /* Use long way over the stack */
3717     oper (flags, val, ops);
3718 }
3719
3720
3721
3722 void g_le (unsigned flags, unsigned long val)
3723 /* Test for less than or equal to */
3724 {
3725     static const char* const ops[4] = {
3726         "tosleax", "tosuleax", "tosleeax", "tosuleeax"
3727     };
3728
3729
3730     /* If the right hand side is const, the lhs is not on stack but still
3731     ** in the primary register.
3732     */
3733     if (flags & CF_CONST) {
3734
3735         /* Look at the type */
3736         switch (flags & CF_TYPEMASK) {
3737
3738             case CF_CHAR:
3739                 if (flags & CF_FORCECHAR) {
3740                     if (flags & CF_UNSIGNED) {
3741                         /* Unsigned compare */
3742                         if (val < 0xFF) {
3743                             /* Use < instead of <= because the former gives
3744                             ** better code on the 6502 than the latter.
3745                             */
3746                             g_lt (flags, val+1);
3747                         } else {
3748                             /* Always true */
3749                             Warning ("Condition is always true");
3750                             AddCodeLine ("jsr return1");
3751                         }
3752                     } else {
3753                         /* Signed compare */
3754                         if ((long) val < 0x7F) {
3755                             /* Use < instead of <= because the former gives
3756                             ** better code on the 6502 than the latter.
3757                             */
3758                             g_lt (flags, val+1);
3759                         } else {
3760                             /* Always true */
3761                             Warning ("Condition is always true");
3762                             AddCodeLine ("jsr return1");
3763                         }
3764                     }
3765                     return;
3766                 }
3767                 /* FALLTHROUGH */
3768
3769             case CF_INT:
3770                 if (flags & CF_UNSIGNED) {
3771                     /* Unsigned compare */
3772                     if (val < 0xFFFF) {
3773                         /* Use < instead of <= because the former gives
3774                         ** better code on the 6502 than the latter.
3775                         */
3776                         g_lt (flags, val+1);
3777                     } else {
3778                         /* Always true */
3779                         Warning ("Condition is always true");
3780                         AddCodeLine ("jsr return1");
3781                     }
3782                 } else {
3783                     /* Signed compare */
3784                     if ((long) val < 0x7FFF) {
3785                         g_lt (flags, val+1);
3786                     } else {
3787                         /* Always true */
3788                         Warning ("Condition is always true");
3789                         AddCodeLine ("jsr return1");
3790                     }
3791                 }
3792                 return;
3793
3794             case CF_LONG:
3795                 if (flags & CF_UNSIGNED) {
3796                     /* Unsigned compare */
3797                     if (val < 0xFFFFFFFF) {
3798                         /* Use < instead of <= because the former gives
3799                         ** better code on the 6502 than the latter.
3800                         */
3801                         g_lt (flags, val+1);
3802                     } else {
3803                         /* Always true */
3804                         Warning ("Condition is always true");
3805                         AddCodeLine ("jsr return1");
3806                     }
3807                 } else {
3808                     /* Signed compare */
3809                     if ((long) val < 0x7FFFFFFF) {
3810                         g_lt (flags, val+1);
3811                     } else {
3812                         /* Always true */
3813                         Warning ("Condition is always true");
3814                         AddCodeLine ("jsr return1");
3815                     }
3816                 }
3817                 return;
3818
3819             default:
3820                 typeerror (flags);
3821         }
3822
3823         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3824         ** into the normal, non-optimized stuff. Note: The standard stuff will
3825         ** always work with ints.
3826         */
3827         flags &= ~CF_FORCECHAR;
3828         g_push (flags & ~CF_CONST, 0);
3829     }
3830
3831     /* Use long way over the stack */
3832     oper (flags, val, ops);
3833 }
3834
3835
3836
3837 void g_gt (unsigned flags, unsigned long val)
3838 /* Test for greater than */
3839 {
3840     static const char* const ops[4] = {
3841         "tosgtax", "tosugtax", "tosgteax", "tosugteax"
3842     };
3843
3844
3845     /* If the right hand side is const, the lhs is not on stack but still
3846     ** in the primary register.
3847     */
3848     if (flags & CF_CONST) {
3849
3850         /* Look at the type */
3851         switch (flags & CF_TYPEMASK) {
3852
3853             case CF_CHAR:
3854                 if (flags & CF_FORCECHAR) {
3855                     if (flags & CF_UNSIGNED) {
3856                         if (val == 0) {
3857                             /* If we have a compare > 0, we will replace it by
3858                             ** != 0 here, since both are identical but the
3859                             ** latter is easier to optimize.
3860                             */
3861                             g_ne (flags, val);
3862                         } else if (val < 0xFF) {
3863                             /* Use >= instead of > because the former gives
3864                             ** better code on the 6502 than the latter.
3865                             */
3866                             g_ge (flags, val+1);
3867                         } else {
3868                             /* Never true */
3869                             Warning ("Condition is never true");
3870                             AddCodeLine ("jsr return0");
3871                         }
3872                     } else {
3873                         if ((long) val < 0x7F) {
3874                             /* Use >= instead of > because the former gives
3875                             ** better code on the 6502 than the latter.
3876                             */
3877                             g_ge (flags, val+1);
3878                         } else {
3879                             /* Never true */
3880                             Warning ("Condition is never true");
3881                             AddCodeLine ("jsr return0");
3882                         }
3883                     }
3884                     return;
3885                 }
3886                 /* FALLTHROUGH */
3887
3888             case CF_INT:
3889                 if (flags & CF_UNSIGNED) {
3890                     /* Unsigned compare */
3891                     if (val == 0) {
3892                         /* If we have a compare > 0, we will replace it by
3893                         ** != 0 here, since both are identical but the latter
3894                         ** is easier to optimize.
3895                         */
3896                         g_ne (flags, val);
3897                     } else if (val < 0xFFFF) {
3898                         /* Use >= instead of > because the former gives better
3899                         ** code on the 6502 than the latter.
3900                         */
3901                         g_ge (flags, val+1);
3902                     } else {
3903                         /* Never true */
3904                         Warning ("Condition is never true");
3905                         AddCodeLine ("jsr return0");
3906                     }
3907                 } else {
3908                     /* Signed compare */
3909                     if ((long) val < 0x7FFF) {
3910                         g_ge (flags, val+1);
3911                     } else {
3912                         /* Never true */
3913                         Warning ("Condition is never true");
3914                         AddCodeLine ("jsr return0");
3915                     }
3916                 }
3917                 return;
3918
3919             case CF_LONG:
3920                 if (flags & CF_UNSIGNED) {
3921                     /* Unsigned compare */
3922                     if (val == 0) {
3923                         /* If we have a compare > 0, we will replace it by
3924                         ** != 0 here, since both are identical but the latter
3925                         ** is easier to optimize.
3926                         */
3927                         g_ne (flags, val);
3928                     } else if (val < 0xFFFFFFFF) {
3929                         /* Use >= instead of > because the former gives better
3930                         ** code on the 6502 than the latter.
3931                         */
3932                         g_ge (flags, val+1);
3933                     } else {
3934                         /* Never true */
3935                         Warning ("Condition is never true");
3936                         AddCodeLine ("jsr return0");
3937                     }
3938                 } else {
3939                     /* Signed compare */
3940                     if ((long) val < 0x7FFFFFFF) {
3941                         g_ge (flags, val+1);
3942                     } else {
3943                         /* Never true */
3944                         Warning ("Condition is never true");
3945                         AddCodeLine ("jsr return0");
3946                     }
3947                 }
3948                 return;
3949
3950             default:
3951                 typeerror (flags);
3952         }
3953
3954         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3955         ** into the normal, non-optimized stuff. Note: The standard stuff will
3956         ** always work with ints.
3957         */
3958         flags &= ~CF_FORCECHAR;
3959         g_push (flags & ~CF_CONST, 0);
3960     }
3961
3962     /* Use long way over the stack */
3963     oper (flags, val, ops);
3964 }
3965
3966
3967
3968 void g_ge (unsigned flags, unsigned long val)
3969 /* Test for greater than or equal to */
3970 {
3971     static const char* const ops[4] = {
3972         "tosgeax", "tosugeax", "tosgeeax", "tosugeeax"
3973     };
3974
3975     unsigned Label;
3976
3977
3978     /* If the right hand side is const, the lhs is not on stack but still
3979     ** in the primary register.
3980     */
3981     if (flags & CF_CONST) {
3982
3983         /* Because the handling of the overflow flag is too complex for
3984         ** inlining, we can handle only unsigned compares, and signed
3985         ** compares against zero here.
3986         */
3987         if (flags & CF_UNSIGNED) {
3988
3989             /* Give a warning in some special cases */
3990             if (val == 0) {
3991                 Warning ("Condition is always true");
3992                 AddCodeLine ("jsr return1");
3993                 return;
3994             }
3995
3996             /* Look at the type */
3997             switch (flags & CF_TYPEMASK) {
3998
3999                 case CF_CHAR:
4000                     if (flags & CF_FORCECHAR) {
4001                         /* Do a subtraction. Condition is true if carry set */
4002                         AddCodeLine ("cmp #$%02X", (unsigned char)val);
4003                         AddCodeLine ("lda #$00");
4004                         AddCodeLine ("ldx #$00");
4005                         AddCodeLine ("rol a");
4006                         return;
4007                     }
4008                     /* FALLTHROUGH */
4009
4010                 case CF_INT:
4011                     /* Do a subtraction. Condition is true if carry set */
4012                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
4013                     AddCodeLine ("txa");
4014                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
4015                     AddCodeLine ("lda #$00");
4016                     AddCodeLine ("ldx #$00");
4017                     AddCodeLine ("rol a");
4018                     return;
4019
4020                 case CF_LONG:
4021                     /* Do a subtraction. Condition is true if carry set */
4022                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
4023                     AddCodeLine ("txa");
4024                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
4025                     AddCodeLine ("lda sreg");
4026                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 16));
4027                     AddCodeLine ("lda sreg+1");
4028                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 24));
4029                     AddCodeLine ("lda #$00");
4030                     AddCodeLine ("ldx #$00");
4031                     AddCodeLine ("rol a");
4032                     return;
4033
4034                 default:
4035                     typeerror (flags);
4036             }
4037
4038         } else if (val == 0) {
4039
4040             /* A signed compare against zero must only look at the sign bit */
4041             switch (flags & CF_TYPEMASK) {
4042
4043                 case CF_CHAR:
4044                     if (flags & CF_FORCECHAR) {
4045                         AddCodeLine ("tax");
4046                         AddCodeLine ("jsr boolge");
4047                         return;
4048                     }
4049                     /* FALLTHROUGH */
4050
4051                 case CF_INT:
4052                     /* Just test the high byte */
4053                     AddCodeLine ("txa");
4054                     AddCodeLine ("jsr boolge");
4055                     return;
4056
4057                 case CF_LONG:
4058                     /* Just test the high byte */
4059                     AddCodeLine ("lda sreg+1");
4060                     AddCodeLine ("jsr boolge");
4061                     return;
4062
4063                 default:
4064                     typeerror (flags);
4065             }
4066
4067         } else {
4068
4069             /* Signed compare against a constant != zero */
4070             switch (flags & CF_TYPEMASK) {
4071
4072                 case CF_CHAR:
4073                     if (flags & CF_FORCECHAR) {
4074                         Label = GetLocalLabel ();
4075                         AddCodeLine ("sec");
4076                         AddCodeLine ("sbc #$%02X", (unsigned char)val);
4077                         AddCodeLine ("bvs %s", LocalLabelName (Label));
4078                         AddCodeLine ("eor #$80");
4079                         g_defcodelabel (Label);
4080                         AddCodeLine ("asl a");          /* Bit 7 -> carry */
4081                         AddCodeLine ("lda #$00");
4082                         AddCodeLine ("ldx #$00");
4083                         AddCodeLine ("rol a");
4084                         return;
4085                     }
4086                     /* FALLTHROUGH */
4087
4088                 case CF_INT:
4089                     /* Do a subtraction */
4090                     Label = GetLocalLabel ();
4091                     AddCodeLine ("cmp #$%02X", (unsigned char)val);
4092                     AddCodeLine ("txa");
4093                     AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
4094                     AddCodeLine ("bvs %s", LocalLabelName (Label));
4095                     AddCodeLine ("eor #$80");
4096                     g_defcodelabel (Label);
4097                     AddCodeLine ("asl a");          /* Bit 7 -> carry */
4098                     AddCodeLine ("lda #$00");
4099                     AddCodeLine ("ldx #$00");
4100                     AddCodeLine ("rol a");
4101                     return;
4102
4103                 case CF_LONG:
4104                     /* This one is too costly */
4105                     break;
4106
4107                 default:
4108                     typeerror (flags);
4109             }
4110         }
4111
4112         /* If we go here, we didn't emit code. Push the lhs on stack and fall
4113         ** into the normal, non-optimized stuff. Note: The standard stuff will
4114         ** always work with ints.
4115         */
4116         flags &= ~CF_FORCECHAR;
4117         g_push (flags & ~CF_CONST, 0);
4118     }
4119
4120     /* Use long way over the stack */
4121     oper (flags, val, ops);
4122 }
4123
4124
4125
4126 /*****************************************************************************/
4127 /*                         Allocating static storage                         */
4128 /*****************************************************************************/
4129
4130
4131
4132 void g_res (unsigned n)
4133 /* Reserve static storage, n bytes */
4134 {
4135     AddDataLine ("\t.res\t%u,$00", n);
4136 }
4137
4138
4139
4140 void g_defdata (unsigned flags, unsigned long val, long offs)
4141 /* Define data with the size given in flags */
4142 {
4143     if (flags & CF_CONST) {
4144
4145         /* Numeric constant */
4146         switch (flags & CF_TYPEMASK) {
4147
4148             case CF_CHAR:
4149                 AddDataLine ("\t.byte\t$%02lX", val & 0xFF);
4150                 break;
4151
4152             case CF_INT:
4153                 AddDataLine ("\t.word\t$%04lX", val & 0xFFFF);
4154                 break;
4155
4156             case CF_LONG:
4157                 AddDataLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
4158                 break;
4159
4160             default:
4161                 typeerror (flags);
4162                 break;
4163
4164         }
4165
4166     } else {
4167
4168         /* Create the correct label name */
4169         const char* Label = GetLabelName (flags, val, offs);
4170
4171         /* Labels are always 16 bit */
4172         AddDataLine ("\t.addr\t%s", Label);
4173
4174     }
4175 }
4176
4177
4178
4179 void g_defbytes (const void* Bytes, unsigned Count)
4180 /* Output a row of bytes as a constant */
4181 {
4182     unsigned Chunk;
4183     char Buf [128];
4184     char* B;
4185
4186     /* Cast the buffer pointer */
4187     const unsigned char* Data = (const unsigned char*) Bytes;
4188
4189     /* Output the stuff */
4190     while (Count) {
4191
4192         /* How many go into this line? */
4193         if ((Chunk = Count) > 16) {
4194             Chunk = 16;
4195         }
4196         Count -= Chunk;
4197
4198         /* Output one line */
4199         strcpy (Buf, "\t.byte\t");
4200         B = Buf + 7;
4201         do {
4202             B += sprintf (B, "$%02X", *Data++);
4203             if (--Chunk) {
4204                 *B++ = ',';
4205             }
4206         } while (Chunk);
4207
4208         /* Output the line */
4209         AddDataLine ("%s", Buf);
4210     }
4211 }
4212
4213
4214
4215 void g_zerobytes (unsigned Count)
4216 /* Output Count bytes of data initialized with zero */
4217 {
4218     if (Count > 0) {
4219         AddDataLine ("\t.res\t%u,$00", Count);
4220     }
4221 }
4222
4223
4224
4225 void g_initregister (unsigned Label, unsigned Reg, unsigned Size)
4226 /* Initialize a register variable from static initialization data */
4227 {
4228     /* Register variables do always have less than 128 bytes */
4229     unsigned CodeLabel = GetLocalLabel ();
4230     AddCodeLine ("ldx #$%02X", (unsigned char) (Size - 1));
4231     g_defcodelabel (CodeLabel);
4232     AddCodeLine ("lda %s,x", GetLabelName (CF_STATIC, Label, 0));
4233     AddCodeLine ("sta %s,x", GetLabelName (CF_REGVAR, Reg, 0));
4234     AddCodeLine ("dex");
4235     AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4236 }
4237
4238
4239
4240 void g_initauto (unsigned Label, unsigned Size)
4241 /* Initialize a local variable at stack offset zero from static data */
4242 {
4243     unsigned CodeLabel = GetLocalLabel ();
4244
4245     CheckLocalOffs (Size);
4246     if (Size <= 128) {
4247         AddCodeLine ("ldy #$%02X", Size-1);
4248         g_defcodelabel (CodeLabel);
4249         AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, Label, 0));
4250         AddCodeLine ("sta (sp),y");
4251         AddCodeLine ("dey");
4252         AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4253     } else if (Size <= 256) {
4254         AddCodeLine ("ldy #$00");
4255         g_defcodelabel (CodeLabel);
4256         AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, Label, 0));
4257         AddCodeLine ("sta (sp),y");
4258         AddCodeLine ("iny");
4259         AddCmpCodeIfSizeNot256 ("cpy #$%02X", Size);
4260         AddCodeLine ("bne %s", LocalLabelName (CodeLabel));
4261     }
4262 }
4263
4264
4265
4266 void g_initstatic (unsigned InitLabel, unsigned VarLabel, unsigned Size)
4267 /* Initialize a static local variable from static initialization data */
4268 {
4269     if (Size <= 128) {
4270         unsigned CodeLabel = GetLocalLabel ();
4271         AddCodeLine ("ldy #$%02X", Size-1);
4272         g_defcodelabel (CodeLabel);
4273         AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, InitLabel, 0));
4274         AddCodeLine ("sta %s,y", GetLabelName (CF_STATIC, VarLabel, 0));
4275         AddCodeLine ("dey");
4276         AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4277     } else if (Size <= 256) {
4278         unsigned CodeLabel = GetLocalLabel ();
4279         AddCodeLine ("ldy #$00");
4280         g_defcodelabel (CodeLabel);
4281         AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, InitLabel, 0));
4282         AddCodeLine ("sta %s,y", GetLabelName (CF_STATIC, VarLabel, 0));
4283         AddCodeLine ("iny");
4284         AddCmpCodeIfSizeNot256 ("cpy #$%02X", Size);
4285         AddCodeLine ("bne %s", LocalLabelName (CodeLabel));
4286     } else {
4287         /* Use the easy way here: memcpy() */
4288         g_getimmed (CF_STATIC, VarLabel, 0);
4289         AddCodeLine ("jsr pushax");
4290         g_getimmed (CF_STATIC, InitLabel, 0);
4291         AddCodeLine ("jsr pushax");
4292         g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, Size, 0);
4293         AddCodeLine ("jsr %s", GetLabelName (CF_EXTERNAL, (uintptr_t) "memcpy", 0));
4294     }
4295 }
4296
4297
4298
4299 /*****************************************************************************/
4300 /*                             Switch statement                              */
4301 /*****************************************************************************/
4302
4303
4304
4305 void g_switch (Collection* Nodes, unsigned DefaultLabel, unsigned Depth)
4306 /* Generate code for a switch statement */
4307 {
4308     unsigned NextLabel = 0;
4309     unsigned I;
4310
4311     /* Setup registers and determine which compare insn to use */
4312     const char* Compare;
4313     switch (Depth) {
4314         case 1:
4315             Compare = "cmp #$%02X";
4316             break;
4317         case 2:
4318             Compare = "cpx #$%02X";
4319             break;
4320         case 3:
4321             AddCodeLine ("ldy sreg");
4322             Compare = "cpy #$%02X";
4323             break;
4324         case 4:
4325             AddCodeLine ("ldy sreg+1");
4326             Compare = "cpy #$%02X";
4327             break;
4328         default:
4329             Internal ("Invalid depth in g_switch: %u", Depth);
4330     }
4331
4332     /* Walk over all nodes */
4333     for (I = 0; I < CollCount (Nodes); ++I) {
4334
4335         /* Get the next case node */
4336         CaseNode* N = CollAtUnchecked (Nodes, I);
4337
4338         /* If we have a next label, define it */
4339         if (NextLabel) {
4340             g_defcodelabel (NextLabel);
4341             NextLabel = 0;
4342         }
4343
4344         /* Do the compare */
4345         AddCodeLine (Compare, CN_GetValue (N));
4346
4347         /* If this is the last level, jump directly to the case code if found */
4348         if (Depth == 1) {
4349
4350             /* Branch if equal */
4351             g_falsejump (0, CN_GetLabel (N));
4352
4353         } else {
4354
4355             /* Determine the next label */
4356             if (I == CollCount (Nodes) - 1) {
4357                 /* Last node means not found */
4358                 g_truejump (0, DefaultLabel);
4359             } else {
4360                 /* Jump to the next check */
4361                 NextLabel = GetLocalLabel ();
4362                 g_truejump (0, NextLabel);
4363             }
4364
4365             /* Check the next level */
4366             g_switch (N->Nodes, DefaultLabel, Depth-1);
4367
4368         }
4369     }
4370
4371     /* If we go here, we haven't found the label */
4372     g_jump (DefaultLabel);
4373 }
4374
4375
4376
4377 /*****************************************************************************/
4378 /*                       User supplied assembler code                        */
4379 /*****************************************************************************/
4380
4381
4382
4383 void g_asmcode (struct StrBuf* B)
4384 /* Output one line of assembler code. */
4385 {
4386     AddCodeLine ("%.*s", (int) SB_GetLen (B), SB_GetConstBuf (B));
4387 }