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