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