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