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