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