]> git.sur5r.net Git - cc65/blob - src/cc65/codegen.c
Fixed some gcc warnings
[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", 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", 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", 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", 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", (val >> 8) & 0xFF);
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", 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", 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", 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", 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", 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", 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", (val >> 8) & 0xFF);
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", 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", val & 0xFF);
1830                 AddCodeLine ("\tsta\t%s", lbuf);
1831                 if (val < 0x100) {
1832                     label = GetLabel ();
1833                     AddCodeLine ("\tbcs\tL%04X", 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", (val >> 8) & 0xFF);
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", val & 0xFF);
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", val & 0xFF);
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", val & 0xFF);
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", val & 0xFF);
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", val & 0xFF);
1994                 AddCodeLine ("\tsta\t(ptr1),y");
1995                 AddCodeLine ("\tpha");
1996                 AddCodeLine ("\tiny");
1997                 AddCodeLine ("\tlda\t(ptr1),y");
1998                 AddCodeLine ("\tsbc\t#$%02X", (val >> 8) & 0xFF);
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", val & 0xFF);
2147                 break;
2148             }
2149             /* FALLTHROUGH */
2150
2151         case CF_INT:
2152             AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
2153             AddCodeLine ("\tbne\t*+4");
2154             AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
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", val & 0xFFFF, label & 0xFFFF);
2419             break;
2420
2421         case CF_LONG:
2422             AddCodeLine ("\t.dword\t$%08X", val);
2423             AddCodeLine ("\t.word\tL%04X", label & 0xFFFF);
2424             break;
2425
2426         default:
2427             typeerror (flags);
2428
2429     }
2430 }
2431
2432
2433
2434 void g_truejump (unsigned flags, unsigned label)
2435 /* Jump to label if zero flag clear */
2436 {
2437     if (flags & CF_SHORT) {
2438         AddCodeLine ("\tbne\tL%04X", label);
2439     } else {
2440         AddCodeLine ("\tjne\tL%04X", label);
2441     }
2442 }
2443
2444
2445
2446 void g_falsejump (unsigned flags, unsigned label)
2447 /* Jump to label if zero flag set */
2448 {
2449     if (flags & CF_SHORT) {
2450         AddCodeLine ("\tbeq\tL%04X", label);
2451     } else {
2452         AddCodeLine ("\tjeq\tL%04X", label);
2453     }
2454 }
2455
2456
2457
2458 static void mod_internal (int k, char* verb1, char* verb2)
2459 {
2460     if (k <= 8) {
2461         AddCodeLine ("\tjsr\t%ssp%c", verb1, k + '0');
2462     } else {
2463         CheckLocalOffs (k);
2464         ldyconst (k);
2465         AddCodeLine ("\tjsr\t%ssp", verb2);
2466     }
2467 }
2468
2469
2470
2471 void g_space (int space)
2472 /* Create or drop space on the stack */
2473 {
2474     if (space < 0) {
2475         mod_internal (-space, "inc", "addy");
2476     } else if (space > 0) {
2477         mod_internal (space, "dec", "suby");
2478     }
2479 }
2480
2481
2482
2483 void g_add (unsigned flags, unsigned long val)
2484 /* Primary = TOS + Primary */
2485 {
2486     static char* ops [12] = {
2487         0,              "tosadda0",     "tosaddax",
2488         0,              "tosadda0",     "tosaddax",
2489         0,              0,              "tosaddeax",
2490         0,              0,              "tosaddeax",
2491     };
2492
2493     if (flags & CF_CONST) {
2494         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2495         g_push (flags & ~CF_CONST, 0);
2496     }
2497     oper (flags, val, ops);
2498 }
2499
2500
2501
2502 void g_sub (unsigned flags, unsigned long val)
2503 /* Primary = TOS - Primary */
2504 {
2505     static char* ops [12] = {
2506         0,              "tossuba0",     "tossubax",
2507         0,              "tossuba0",     "tossubax",
2508         0,              0,              "tossubeax",
2509         0,              0,              "tossubeax",
2510     };
2511
2512     if (flags & CF_CONST) {
2513         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2514         g_push (flags & ~CF_CONST, 0);
2515     }
2516     oper (flags, val, ops);
2517 }
2518
2519
2520
2521 void g_rsub (unsigned flags, unsigned long val)
2522 /* Primary = Primary - TOS */
2523 {
2524     static char* ops [12] = {
2525         0,              "tosrsuba0",    "tosrsubax",
2526         0,              "tosrsuba0",    "tosrsubax",
2527         0,              0,              "tosrsubeax",
2528         0,              0,              "tosrsubeax",
2529     };
2530     oper (flags, val, ops);
2531 }
2532
2533
2534
2535 void g_mul (unsigned flags, unsigned long val)
2536 /* Primary = TOS * Primary */
2537 {
2538     static char* ops [12] = {
2539         0,              "tosmula0",     "tosmulax",
2540         0,              "tosumula0",    "tosumulax",
2541         0,              0,              "tosmuleax",
2542         0,              0,              "tosumuleax",
2543     };
2544
2545     int p2;
2546
2547     /* Do strength reduction if the value is constant and a power of two */
2548     if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2549         /* Generate a shift instead */
2550         g_asl (flags, p2);
2551         return;
2552     }
2553
2554     /* If the right hand side is const, the lhs is not on stack but still
2555      * in the primary register.                           
2556      */
2557     if (flags & CF_CONST) {
2558
2559         switch (flags & CF_TYPE) {
2560
2561             case CF_CHAR:
2562                 if (flags & CF_FORCECHAR) {
2563                     /* Handle some special cases */
2564                     switch (val) {
2565
2566                         case 3:
2567                             AddCodeLine ("\tsta\ttmp1");
2568                             AddCodeLine ("\tasl\ta");
2569                             AddCodeLine ("\tclc");
2570                             AddCodeLine ("\tadc\ttmp1");
2571                             return;
2572
2573                         case 5:
2574                             AddCodeLine ("\tsta\ttmp1");
2575                             AddCodeLine ("\tasl\ta");
2576                             AddCodeLine ("\tasl\ta");
2577                             AddCodeLine ("\tclc");
2578                             AddCodeLine ("\tadc\ttmp1");
2579                             return;
2580
2581                         case 10:
2582                             AddCodeLine ("\tsta\ttmp1");
2583                             AddCodeLine ("\tasl\ta");
2584                             AddCodeLine ("\tasl\ta");
2585                             AddCodeLine ("\tclc");
2586                             AddCodeLine ("\tadc\ttmp1");
2587                             AddCodeLine ("\tasl\ta");
2588                             return;
2589                     }
2590                 }
2591                 /* FALLTHROUGH */
2592
2593             case CF_INT:
2594                 break;
2595
2596             case CF_LONG:
2597                 break;
2598
2599             default:
2600                 typeerror (flags);
2601         }
2602
2603         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2604          * into the normal, non-optimized stuff.
2605          */
2606         flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2607         g_push (flags & ~CF_CONST, 0);
2608
2609     }
2610
2611     /* Use long way over the stack */
2612     oper (flags, val, ops);
2613 }
2614
2615
2616
2617 void g_div (unsigned flags, unsigned long val)
2618 /* Primary = TOS / Primary */
2619 {
2620     static char* ops [12] = {
2621         0,              "tosdiva0",     "tosdivax",
2622         0,              "tosudiva0",    "tosudivax",
2623         0,              0,              "tosdiveax",
2624         0,              0,              "tosudiveax",
2625     };
2626
2627     /* Do strength reduction if the value is constant and a power of two */
2628     int p2;
2629     if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2630         /* Generate a shift instead */
2631         g_asr (flags, p2);
2632     } else {
2633         /* Generate a division */
2634         if (flags & CF_CONST) {
2635             /* lhs is not on stack */
2636             flags &= ~CF_FORCECHAR;     /* Handle chars as ints */
2637             g_push (flags & ~CF_CONST, 0);
2638         }
2639         oper (flags, val, ops);
2640     }
2641 }
2642
2643
2644
2645 void g_mod (unsigned flags, unsigned long val)
2646 /* Primary = TOS % Primary */
2647 {
2648     static char* ops [12] = {
2649         0,              "tosmoda0",     "tosmodax",
2650         0,              "tosumoda0",    "tosumodax",
2651         0,              0,              "tosmodeax",
2652         0,              0,              "tosumodeax",
2653     };
2654     int p2;
2655
2656     /* Check if we can do some cost reduction */
2657     if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2658         /* We can do that with an AND operation */
2659         g_and (flags, val - 1);
2660     } else {
2661         /* Do it the hard way... */
2662         if (flags & CF_CONST) {
2663             /* lhs is not on stack */
2664             flags &= ~CF_FORCECHAR;     /* Handle chars as ints */
2665             g_push (flags & ~CF_CONST, 0);
2666         }
2667         oper (flags, val, ops);
2668     }
2669 }
2670
2671
2672
2673 void g_or (unsigned flags, unsigned long val)
2674 /* Primary = TOS | Primary */
2675 {
2676     static char* ops [12] = {
2677         0,              "tosora0",      "tosorax",
2678         0,              "tosora0",      "tosorax",
2679         0,              0,              "tosoreax",
2680         0,              0,              "tosoreax",
2681     };
2682
2683     /* If the right hand side is const, the lhs is not on stack but still
2684      * in the primary register.
2685      */
2686     if (flags & CF_CONST) {
2687
2688         switch (flags & CF_TYPE) {
2689
2690             case CF_CHAR:
2691                 if (flags & CF_FORCECHAR) {
2692                     if ((val & 0xFF) != 0xFF) {
2693                         AddCodeLine ("\tora\t#$%02X", val & 0xFF);
2694                     }
2695                     return;
2696                 }
2697                 /* FALLTHROUGH */
2698
2699             case CF_INT:
2700                 if (val <= 0xFF) {
2701                     AddCodeLine ("\tora\t#$%02X", val & 0xFF);
2702                     return;
2703                 }
2704                 break;
2705
2706             case CF_LONG:
2707                 if (val <= 0xFF) {
2708                     AddCodeLine ("\tora\t#$%02X", val & 0xFF);
2709                     return;
2710                 }
2711                 break;
2712
2713             default:
2714                 typeerror (flags);
2715         }
2716
2717         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2718          * into the normal, non-optimized stuff.
2719          */
2720         g_push (flags & ~CF_CONST, 0);
2721
2722     }
2723
2724     /* Use long way over the stack */
2725     oper (flags, val, ops);
2726 }
2727
2728
2729
2730 void g_xor (unsigned flags, unsigned long val)
2731 /* Primary = TOS ^ Primary */
2732 {
2733     static char* ops [12] = {
2734         0,              "tosxora0",     "tosxorax",
2735         0,              "tosxora0",     "tosxorax",
2736         0,              0,              "tosxoreax",
2737         0,              0,              "tosxoreax",
2738     };
2739
2740
2741     /* If the right hand side is const, the lhs is not on stack but still
2742      * in the primary register.
2743      */
2744     if (flags & CF_CONST) {
2745
2746         switch (flags & CF_TYPE) {
2747
2748             case CF_CHAR:
2749                 if (flags & CF_FORCECHAR) {
2750                     if ((val & 0xFF) != 0) {
2751                         AddCodeLine ("\teor\t#$%02X", val & 0xFF);
2752                     }
2753                     return;
2754                 }
2755                 /* FALLTHROUGH */
2756
2757             case CF_INT:
2758                 if (val <= 0xFF) {
2759                     if (val != 0) {
2760                         AddCodeLine ("\teor\t#$%02X", val);
2761                     }
2762                     return;
2763                 } else if ((val & 0xFF) == 0) {
2764                     AddCodeLine ("\tpha");
2765                     AddCodeLine ("\ttxa");
2766                     AddCodeLine ("\teor\t#$%02X", (val >> 8) & 0xFF);
2767                     AddCodeLine ("\ttax");
2768                     AddCodeLine ("\tpla");
2769                     return;
2770                 }
2771                 break;
2772
2773             case CF_LONG:
2774                 if (val <= 0xFF) {
2775                     if (val != 0) {
2776                         AddCodeLine ("\teor\t#$%02X", val & 0xFF);
2777                     }
2778                     return;
2779                 }
2780                 break;
2781
2782             default:
2783                 typeerror (flags);
2784         }
2785
2786         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2787          * into the normal, non-optimized stuff.
2788          */
2789         g_push (flags & ~CF_CONST, 0);
2790
2791     }
2792
2793     /* Use long way over the stack */
2794     oper (flags, val, ops);
2795 }
2796
2797
2798
2799 void g_and (unsigned flags, unsigned long val)
2800 /* Primary = TOS & Primary */
2801 {
2802     static char* ops [12] = {
2803         0,              "tosanda0",     "tosandax",
2804         0,              "tosanda0",     "tosandax",
2805         0,              0,              "tosandeax",
2806         0,              0,              "tosandeax",
2807     };
2808
2809     /* If the right hand side is const, the lhs is not on stack but still
2810      * in the primary register.
2811      */
2812     if (flags & CF_CONST) {
2813
2814         switch (flags & CF_TYPE) {
2815
2816             case CF_CHAR:
2817                 if (flags & CF_FORCECHAR) {
2818                     AddCodeLine ("\tand\t#$%02X", val & 0xFF);
2819                     return;
2820                 }
2821                 /* FALLTHROUGH */
2822             case CF_INT:
2823                 if ((val & 0xFFFF) != 0xFFFF) {
2824                     if (val <= 0xFF) {
2825                         ldxconst (0);
2826                         if (val == 0) {
2827                             ldaconst (0);
2828                         } else if (val != 0xFF) {
2829                             AddCodeLine ("\tand\t#$%02X", val & 0xFF);
2830                         }
2831                     } else if ((val & 0xFF00) == 0xFF00) {
2832                         AddCodeLine ("\tand\t#$%02X", val & 0xFF);
2833                     } else if ((val & 0x00FF) == 0x0000) {
2834                         AddCodeLine ("\ttxa");
2835                         AddCodeLine ("\tand\t#$%02X", (val >> 8) & 0xFF);
2836                         AddCodeLine ("\ttax");
2837                         ldaconst (0);
2838                     } else {
2839                         AddCodeLine ("\ttay");
2840                         AddCodeLine ("\ttxa");
2841                         AddCodeLine ("\tand\t#$%02X", (val >> 8) & 0xFF);
2842                         AddCodeLine ("\ttax");
2843                         AddCodeLine ("\ttya");
2844                         if ((val & 0x00FF) != 0x00FF) {
2845                             AddCodeLine ("\tand\t#$%02X", val & 0xFF);
2846                         }
2847                     }
2848                 }
2849                 return;
2850
2851             case CF_LONG:
2852                 if (val <= 0xFF) {
2853                     ldxconst (0);
2854                     AddCodeLine ("\tstx\tsreg+1");
2855                     AddCodeLine ("\tstx\tsreg");
2856                     if ((val & 0xFF) != 0xFF) {
2857                          AddCodeLine ("\tand\t#$%02X", val & 0xFF);
2858                     }
2859                     return;
2860                 } else if (val == 0xFF00) {
2861                     ldaconst (0);
2862                     AddCodeLine ("\tsta\tsreg+1");
2863                     AddCodeLine ("\tsta\tsreg");
2864                     return;
2865                 }
2866                 break;
2867
2868             default:
2869                 typeerror (flags);
2870         }
2871
2872         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2873          * into the normal, non-optimized stuff.
2874          */
2875         g_push (flags & ~CF_CONST, 0);
2876
2877     }
2878
2879     /* Use long way over the stack */
2880     oper (flags, val, ops);
2881 }
2882
2883
2884
2885 void g_asr (unsigned flags, unsigned long val)
2886 /* Primary = TOS >> Primary */
2887 {
2888     static char* ops [12] = {
2889         0,              "tosasra0",     "tosasrax",
2890         0,              "tosshra0",     "tosshrax",
2891         0,              0,              "tosasreax",
2892         0,              0,              "tosshreax",
2893     };
2894
2895     /* If the right hand side is const, the lhs is not on stack but still
2896      * in the primary register.
2897      */
2898     if (flags & CF_CONST) {
2899
2900         switch (flags & CF_TYPE) {
2901
2902             case CF_CHAR:
2903             case CF_INT:
2904                 if (val >= 1 && val <= 3) {
2905                     if (flags & CF_UNSIGNED) {
2906                         AddCodeLine ("\tjsr\tshrax%ld", val);
2907                     } else {
2908                         AddCodeLine ("\tjsr\tasrax%ld", val);
2909                     }
2910                     return;
2911                 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2912                     AddCodeLine ("\ttxa");
2913                     ldxconst (0);
2914                     return;
2915                 }
2916                 break;
2917
2918             case CF_LONG:
2919                 if (val >= 1 && val <= 3) {
2920                     if (flags & CF_UNSIGNED) {
2921                         AddCodeLine ("\tjsr\tshreax%ld", val);
2922                     } else {
2923                         AddCodeLine ("\tjsr\tasreax%ld", val);
2924                     }
2925                     return;
2926                 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2927                     AddCodeLine ("\ttxa");
2928                     AddCodeLine ("\tldx\tsreg");
2929                     AddCodeLine ("\tldy\tsreg+1");
2930                     AddCodeLine ("\tsty\tsreg");
2931                     AddCodeLine ("\tldy\t#$00");
2932                     AddCodeLine ("\tsty\tsreg+1");
2933                     return;
2934                 } else if (val == 16) {
2935                     AddCodeLine ("\tldy\t#$00");
2936                     AddCodeLine ("\tldx\tsreg+1");
2937                     if ((flags & CF_UNSIGNED) == 0) {
2938                         AddCodeLine ("\tbpl\t*+3");
2939                         AddCodeLine ("\tdey");
2940                         AddCodeHint ("y:!");
2941                     }
2942                     AddCodeLine ("\tlda\tsreg");
2943                     AddCodeLine ("\tsty\tsreg+1");
2944                     AddCodeLine ("\tsty\tsreg");
2945                     return;
2946                 }
2947                 break;
2948
2949             default:
2950                 typeerror (flags);
2951         }
2952
2953         /* If we go here, we didn't emit code. Push the lhs on stack and fall
2954          * into the normal, non-optimized stuff.
2955          */
2956         g_push (flags & ~CF_CONST, 0);
2957
2958     }
2959
2960     /* Use long way over the stack */
2961     oper (flags, val, ops);
2962 }
2963
2964
2965
2966 void g_asl (unsigned flags, unsigned long val)
2967 /* Primary = TOS << Primary */
2968 {
2969     static char* ops [12] = {
2970         0,              "tosasla0",     "tosaslax",
2971         0,              "tosshla0",     "tosshlax",
2972         0,              0,              "tosasleax",
2973         0,              0,              "tosshleax",
2974     };
2975
2976
2977     /* If the right hand side is const, the lhs is not on stack but still
2978      * in the primary register.
2979      */
2980     if (flags & CF_CONST) {
2981
2982         switch (flags & CF_TYPE) {
2983
2984             case CF_CHAR:
2985             case CF_INT:
2986                 if (val >= 1 && val <= 3) {
2987                     if (flags & CF_UNSIGNED) {
2988                         AddCodeLine ("\tjsr\tshlax%ld", val);
2989                     } else {
2990                         AddCodeLine ("\tjsr\taslax%ld", val);
2991                     }
2992                     return;
2993                 } else if (val == 8) {
2994                     AddCodeLine ("\ttax");
2995                     AddCodeLine ("\tlda\t#$00");
2996                     return;
2997                 }
2998                 break;
2999
3000             case CF_LONG:
3001                 if (val >= 1 && val <= 3) {
3002                     if (flags & CF_UNSIGNED) {
3003                         AddCodeLine ("\tjsr\tshleax%ld", val);
3004                     } else {
3005                         AddCodeLine ("\tjsr\tasleax%ld", val);
3006                     }
3007                     return;
3008                 } else if (val == 8) {
3009                     AddCodeLine ("\tldy\tsreg");
3010                     AddCodeLine ("\tsty\tsreg+1");
3011                     AddCodeLine ("\tstx\tsreg");
3012                     AddCodeLine ("\ttax");
3013                     AddCodeLine ("\tlda\t#$00");
3014                     return;
3015                 } else if (val == 16) {
3016                     AddCodeLine ("\tstx\tsreg+1");
3017                     AddCodeLine ("\tsta\tsreg");
3018                     AddCodeLine ("\tlda\t#$00");
3019                     AddCodeLine ("\ttax");
3020                     return;
3021                 }
3022                 break;
3023
3024             default:
3025                 typeerror (flags);
3026         }
3027
3028         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3029          * into the normal, non-optimized stuff.
3030          */
3031         g_push (flags & ~CF_CONST, 0);
3032
3033     }
3034
3035     /* Use long way over the stack */
3036     oper (flags, val, ops);
3037 }
3038
3039
3040
3041 void g_neg (unsigned flags)
3042 /* Primary = -Primary */
3043 {
3044     switch (flags & CF_TYPE) {
3045
3046         case CF_CHAR:
3047         case CF_INT:
3048             AddCodeLine ("\tjsr\tnegax");
3049             break;
3050
3051         case CF_LONG:
3052             AddCodeLine ("\tjsr\tnegeax");
3053             break;
3054
3055         default:
3056             typeerror (flags);
3057     }
3058 }
3059
3060
3061
3062 void g_bneg (unsigned flags)
3063 /* Primary = !Primary */
3064 {
3065     switch (flags & CF_TYPE) {
3066
3067         case CF_CHAR:
3068             AddCodeLine ("\tjsr\tbnega");
3069             break;
3070
3071         case CF_INT:
3072             AddCodeLine ("\tjsr\tbnegax");
3073             break;
3074
3075         case CF_LONG:
3076             AddCodeLine ("\tjsr\tbnegeax");
3077             break;
3078
3079         default:
3080             typeerror (flags);
3081     }
3082 }
3083
3084
3085
3086 void g_com (unsigned flags)
3087 /* Primary = ~Primary */
3088 {
3089     switch (flags & CF_TYPE) {
3090
3091         case CF_CHAR:
3092         case CF_INT:
3093             AddCodeLine ("\tjsr\tcomplax");
3094             break;
3095
3096         case CF_LONG:
3097             AddCodeLine ("\tjsr\tcompleax");
3098             break;
3099
3100         default:
3101             typeerror (flags);
3102     }
3103 }
3104
3105
3106
3107 void g_inc (unsigned flags, unsigned long val)
3108 /* Increment the primary register by a given number */
3109 {
3110     /* Don't inc by zero */
3111     if (val == 0) {
3112         return;
3113     }
3114
3115     /* Generate code for the supported types */
3116     flags &= ~CF_CONST;
3117     switch (flags & CF_TYPE) {
3118
3119         case CF_CHAR:
3120             if (flags & CF_FORCECHAR) {
3121                 if (CPU == CPU_65C02 && val <= 2) {
3122                     while (val--) {
3123                         AddCodeLine ("\tina");
3124                     }
3125                 } else {
3126                     AddCodeLine ("\tclc");
3127                     AddCodeLine ("\tadc\t#$%02X", val & 0xFF);
3128                 }
3129                 break;
3130             }
3131             /* FALLTHROUGH */
3132
3133         case CF_INT:
3134             if (CPU == CPU_65C02 && val == 1) {
3135                 AddCodeLine ("\tina");
3136                 AddCodeLine ("\tbne\t*+3");
3137                 AddCodeLine ("\tinx");
3138                 /* Tell the optimizer that the X register may be invalid */
3139                 AddCodeHint ("x:!");
3140             } else if (FavourSize) {
3141                 /* Use jsr calls */
3142                 if (val <= 8) {
3143                     AddCodeLine ("\tjsr\tincax%u", val);
3144                 } else if (val <= 255) {
3145                     ldyconst (val);
3146                     AddCodeLine ("\tjsr\tincaxy");
3147                 } else {
3148                     g_add (flags | CF_CONST, val);
3149                 }
3150             } else {
3151                 /* Inline the code */
3152                 if (val < 0x300) {
3153                     if ((val & 0xFF) != 0) {
3154                         AddCodeLine ("\tclc");
3155                         AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
3156                         AddCodeLine ("\tbcc\t*+3");
3157                         AddCodeLine ("\tinx");
3158                         /* Tell the optimizer that the X register may be invalid */
3159                         AddCodeHint ("x:!");
3160                     }
3161                     if (val >= 0x100) {
3162                         AddCodeLine ("\tinx");
3163                     }
3164                     if (val >= 0x200) {
3165                         AddCodeLine ("\tinx");
3166                     }
3167                 } else {
3168                     AddCodeLine ("\tclc");
3169                     if ((val & 0xFF) != 0) {
3170                         AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
3171                         /* Tell the optimizer that the X register may be invalid */
3172                         AddCodeHint ("x:!");
3173                     }
3174                     AddCodeLine ("\tpha");
3175                     AddCodeLine ("\ttxa");
3176                     AddCodeLine ("\tadc\t#$%02X", (unsigned char) (val >> 8));
3177                     AddCodeLine ("\ttax");
3178                     AddCodeLine ("\tpla");
3179                 }
3180             }
3181             break;
3182
3183         case CF_LONG:
3184             if (val <= 255) {
3185                 ldyconst (val);
3186                 AddCodeLine ("\tjsr\tinceaxy");
3187             } else {
3188                 g_add (flags | CF_CONST, val);
3189             }
3190             break;
3191
3192         default:
3193             typeerror (flags);
3194
3195     }
3196 }
3197
3198
3199
3200 void g_dec (unsigned flags, unsigned long val)
3201 /* Decrement the primary register by a given number */
3202 {
3203     /* Generate code for the supported types */
3204     flags &= ~CF_CONST;
3205     switch (flags & CF_TYPE) {
3206
3207         case CF_CHAR:
3208             if (flags & CF_FORCECHAR) {
3209                 if (CPU == CPU_65C02 && val <= 2) {
3210                     while (val--) {
3211                         AddCodeLine ("\tdea");
3212                     }
3213                 } else {
3214                     AddCodeLine ("\tsec");
3215                     AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
3216                 }
3217                 break;
3218             }
3219             /* FALLTHROUGH */
3220
3221         case CF_INT:
3222             if (val <= 2) {
3223                 AddCodeLine ("\tjsr\tdecax%d", (int) val);
3224             } else if (val <= 255) {
3225                 ldyconst (val);
3226                 AddCodeLine ("\tjsr\tdecaxy");
3227             } else {
3228                 g_sub (flags | CF_CONST, val);
3229             }
3230             break;
3231
3232         case CF_LONG:
3233             if (val <= 255) {
3234                 ldyconst (val);
3235                 AddCodeLine ("\tjsr\tdeceaxy");
3236             } else {
3237                 g_sub (flags | CF_CONST, val);
3238             }
3239             break;
3240
3241         default:
3242             typeerror (flags);
3243
3244     }
3245 }
3246
3247
3248
3249 /*
3250  * Following are the conditional operators. They compare the TOS against
3251  * the primary and put a literal 1 in the primary if the condition is
3252  * true, otherwise they clear the primary register
3253  */
3254
3255
3256
3257 void g_eq (unsigned flags, unsigned long val)
3258 /* Test for equal */
3259 {
3260     static char* ops [12] = {
3261         "toseq00",      "toseqa0",      "toseqax",
3262         "toseq00",      "toseqa0",      "toseqax",
3263         0,              0,              "toseqeax",
3264         0,              0,              "toseqeax",
3265     };
3266
3267     /* If the right hand side is const, the lhs is not on stack but still
3268      * in the primary register.
3269      */
3270     if (flags & CF_CONST) {
3271
3272         switch (flags & CF_TYPE) {
3273
3274             case CF_CHAR:
3275                 if (flags & CF_FORCECHAR) {
3276                     AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3277                     AddCodeLine ("\tjsr\tbooleq");
3278                     return;
3279                 }
3280                 /* FALLTHROUGH */
3281
3282             case CF_INT:
3283                 AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
3284                 AddCodeLine ("\tbne\t*+4");
3285                 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3286                 AddCodeLine ("\tjsr\tbooleq");
3287                 return;
3288
3289             case CF_LONG:
3290                 break;
3291
3292             default:
3293                 typeerror (flags);
3294         }
3295
3296         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3297          * into the normal, non-optimized stuff.
3298          */
3299         g_push (flags & ~CF_CONST, 0);
3300
3301     }
3302
3303     /* Use long way over the stack */
3304     oper (flags, val, ops);
3305 }
3306
3307
3308
3309 void g_ne (unsigned flags, unsigned long val)
3310 /* Test for not equal */
3311 {
3312     static char* ops [12] = {
3313         "tosne00",      "tosnea0",      "tosneax",
3314         "tosne00",      "tosnea0",      "tosneax",
3315         0,              0,              "tosneeax",
3316         0,              0,              "tosneeax",
3317     };
3318
3319
3320     /* If the right hand side is const, the lhs is not on stack but still
3321      * in the primary register.
3322      */
3323     if (flags & CF_CONST) {
3324
3325         switch (flags & CF_TYPE) {
3326
3327             case CF_CHAR:
3328                 if (flags & CF_FORCECHAR) {
3329                     AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3330                     AddCodeLine ("\tjsr\tboolne");
3331                     return;
3332                 }
3333                 /* FALLTHROUGH */
3334
3335             case CF_INT:
3336                 AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
3337                 AddCodeLine ("\tbne\t*+4");
3338                 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3339                 AddCodeLine ("\tjsr\tboolne");
3340                 return;
3341
3342             case CF_LONG:
3343                 break;
3344
3345             default:
3346                 typeerror (flags);
3347         }
3348
3349         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3350          * into the normal, non-optimized stuff.
3351          */
3352         g_push (flags & ~CF_CONST, 0);
3353
3354     }
3355
3356     /* Use long way over the stack */
3357     oper (flags, val, ops);
3358 }
3359
3360
3361
3362 void g_lt (unsigned flags, unsigned long val)
3363 /* Test for less than */
3364 {
3365     static char* ops [12] = {
3366         "toslt00",      "toslta0",      "tosltax",
3367         "tosult00",     "tosulta0",     "tosultax",
3368         0,              0,              "toslteax",
3369         0,              0,              "tosulteax",
3370     };
3371
3372     /* If the right hand side is const, the lhs is not on stack but still
3373      * in the primary register.
3374      */
3375     if (flags & CF_CONST) {
3376
3377         /* Give a warning in some special cases */
3378         if ((flags & CF_UNSIGNED) && val == 0) {
3379             Warning (WARN_COND_NEVER_TRUE);
3380         }
3381
3382         /* Look at the type */
3383         switch (flags & CF_TYPE) {
3384
3385             case CF_CHAR:
3386                 if (flags & CF_FORCECHAR) {
3387                     AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3388                     if (flags & CF_UNSIGNED) {
3389                         AddCodeLine ("\tjsr\tboolult");
3390                     } else {
3391                         AddCodeLine ("\tjsr\tboollt");
3392                     }
3393                     return;
3394                 }
3395                 /* FALLTHROUGH */
3396
3397             case CF_INT:
3398                 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3399                     /* If we have a signed compare against zero, we only need to
3400                      * test the high byte.
3401                      */
3402                     AddCodeLine ("\ttxa");
3403                     AddCodeLine ("\tjsr\tboollt");
3404                     return;
3405                 }
3406                 /* Direct code only for unsigned data types */
3407                 if (flags & CF_UNSIGNED) {
3408                     AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
3409                     AddCodeLine ("\tbne\t*+4");
3410                     AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3411                     AddCodeLine ("\tjsr\tboolult");
3412                     return;
3413                 }
3414                 break;
3415
3416             case CF_LONG:
3417                 break;
3418
3419             default:
3420                 typeerror (flags);
3421         }
3422
3423         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3424          * into the normal, non-optimized stuff.
3425          */
3426         g_push (flags & ~CF_CONST, 0);
3427
3428     }
3429
3430     /* Use long way over the stack */
3431     oper (flags, val, ops);
3432 }
3433
3434
3435
3436 void g_le (unsigned flags, unsigned long val)
3437 /* Test for less than or equal to */
3438 {
3439     static char* ops [12] = {
3440         "tosle00",      "toslea0",      "tosleax",
3441         "tosule00",     "tosulea0",     "tosuleax",
3442         0,              0,              "tosleeax",
3443         0,              0,              "tosuleeax",
3444     };
3445
3446
3447     /* If the right hand side is const, the lhs is not on stack but still
3448      * in the primary register.
3449      */
3450     if (flags & CF_CONST) {
3451
3452         /* Look at the type */
3453         switch (flags & CF_TYPE) {
3454
3455             case CF_CHAR:
3456                 if (flags & CF_FORCECHAR) {
3457                     AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3458                     if (flags & CF_UNSIGNED) {
3459                         AddCodeLine ("\tjsr\tboolule");
3460                     } else {
3461                         AddCodeLine ("\tjsr\tboolle");
3462                     }
3463                     return;
3464                 }
3465                 /* FALLTHROUGH */
3466
3467             case CF_INT:
3468                 if (flags & CF_UNSIGNED) {
3469                     AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
3470                     AddCodeLine ("\tbne\t*+4");
3471                     AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3472                     AddCodeLine ("\tjsr\tboolule");
3473                     return;
3474                 }
3475                 break;
3476
3477             case CF_LONG:
3478                 break;
3479
3480             default:
3481                 typeerror (flags);
3482         }
3483
3484         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3485          * into the normal, non-optimized stuff.
3486          */
3487         g_push (flags & ~CF_CONST, 0);
3488
3489     }
3490
3491     /* Use long way over the stack */
3492     oper (flags, val, ops);
3493 }
3494
3495
3496
3497 void g_gt (unsigned flags, unsigned long val)
3498 /* Test for greater than */
3499 {
3500     static char* ops [12] = {
3501         "tosgt00",      "tosgta0",      "tosgtax",
3502         "tosugt00",     "tosugta0",     "tosugtax",
3503         0,              0,              "tosgteax",
3504         0,              0,              "tosugteax",
3505     };
3506
3507
3508     /* If the right hand side is const, the lhs is not on stack but still
3509      * in the primary register.
3510      */
3511     if (flags & CF_CONST) {
3512
3513         /* Look at the type */
3514         switch (flags & CF_TYPE) {
3515
3516             case CF_CHAR:
3517                 if (flags & CF_FORCECHAR) {
3518                     AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3519                     if (flags & CF_UNSIGNED) {
3520                         /* If we have a compare > 0, we will replace it by
3521                          * != 0 here, since both are identical but the latter
3522                          * is easier to optimize.
3523                          */
3524                         if (val & 0xFF) {
3525                             AddCodeLine ("\tjsr\tboolugt");
3526                         } else {
3527                             AddCodeLine ("\tjsr\tboolne");
3528                         }
3529                     } else {
3530                         AddCodeLine ("\tjsr\tboolgt");
3531                     }
3532                     return;
3533                 }
3534                 /* FALLTHROUGH */
3535
3536             case CF_INT:
3537                 if (flags & CF_UNSIGNED) {
3538                     /* If we have a compare > 0, we will replace it by
3539                      * != 0 here, since both are identical but the latter
3540                      * is easier to optimize.
3541                      */
3542                     if ((val & 0xFFFF) == 0) {
3543                         AddCodeLine ("\tstx\ttmp1");
3544                         AddCodeLine ("\tora\ttmp1");
3545                         AddCodeLine ("\tjsr\tboolne");
3546                     } else {
3547                         AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
3548                         AddCodeLine ("\tbne\t*+4");
3549                         AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3550                         AddCodeLine ("\tjsr\tboolugt");
3551                     }
3552                     return;
3553                 }
3554                 break;
3555
3556             case CF_LONG:
3557                 break;
3558
3559             default:
3560                 typeerror (flags);
3561         }
3562
3563         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3564          * into the normal, non-optimized stuff.
3565          */
3566         g_push (flags & ~CF_CONST, 0);
3567
3568     }
3569
3570     /* Use long way over the stack */
3571     oper (flags, val, ops);
3572 }
3573
3574
3575
3576 void g_ge (unsigned flags, unsigned long val)
3577 /* Test for greater than or equal to */
3578 {
3579     static char* ops [12] = {
3580         "tosge00",      "tosgea0",      "tosgeax",
3581         "tosuge00",     "tosugea0",     "tosugeax",
3582         0,              0,              "tosgeeax",
3583         0,              0,              "tosugeeax",
3584     };
3585
3586
3587     /* If the right hand side is const, the lhs is not on stack but still
3588      * in the primary register.
3589      */
3590     if (flags & CF_CONST) {
3591
3592         /* Give a warning in some special cases */
3593         if ((flags & CF_UNSIGNED) && val == 0) {
3594             Warning (WARN_COND_ALWAYS_TRUE);
3595         }
3596
3597         /* Look at the type */
3598         switch (flags & CF_TYPE) {
3599
3600             case CF_CHAR:
3601                 if (flags & CF_FORCECHAR) {
3602                     AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3603                     if (flags & CF_UNSIGNED) {
3604                         AddCodeLine ("\tjsr\tbooluge");
3605                     } else {
3606                         AddCodeLine ("\tjsr\tboolge");
3607                     }
3608                     return;
3609                 }
3610                 /* FALLTHROUGH */
3611
3612             case CF_INT:
3613                 if (flags & CF_UNSIGNED) {
3614                     AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
3615                     AddCodeLine ("\tbne\t*+4");
3616                     AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3617                     AddCodeLine ("\tjsr\tbooluge");
3618                     return;
3619                 }
3620                 break;
3621
3622             case CF_LONG:
3623                 break;
3624
3625             default:
3626                 typeerror (flags);
3627         }
3628
3629         /* If we go here, we didn't emit code. Push the lhs on stack and fall
3630          * into the normal, non-optimized stuff.
3631          */
3632         g_push (flags & ~CF_CONST, 0);
3633
3634     }
3635
3636     /* Use long way over the stack */
3637     oper (flags, val, ops);
3638 }
3639
3640
3641
3642 /*****************************************************************************/
3643 /*                         Allocating static storage                         */
3644 /*****************************************************************************/
3645
3646
3647
3648 void g_res (unsigned n)
3649 /* Reserve static storage, n bytes */
3650 {
3651     AddCodeLine ("\t.res\t%u,$00", n);
3652 }
3653
3654
3655
3656 void g_defdata (unsigned flags, unsigned long val, unsigned offs)
3657 /* Define data with the size given in flags */
3658 {
3659     if (flags & CF_CONST) {
3660
3661         /* Numeric constant */
3662         switch (flags & CF_TYPE) {
3663
3664             case CF_CHAR:
3665                 AddCodeLine ("\t.byte\t$%02lX", val & 0xFF);
3666                 break;
3667
3668             case CF_INT:
3669                 AddCodeLine ("\t.word\t$%04lX", val & 0xFFFF);
3670                 break;
3671
3672             case CF_LONG:
3673                 AddCodeLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
3674                 break;
3675
3676             default:
3677                 typeerror (flags);
3678                 break;
3679
3680         }
3681
3682     } else {
3683
3684         /* Create the correct label name */
3685         const char* Label = GetLabelName (flags, val, offs);
3686
3687         /* Labels are always 16 bit */
3688         AddCodeLine ("\t.word\t%s", Label);
3689
3690     }
3691 }
3692
3693
3694
3695 void g_defbytes (const unsigned char* Bytes, unsigned Count)
3696 /* Output a row of bytes as a constant */
3697 {
3698     unsigned Chunk;
3699     char Buf [128];
3700     char* B;
3701
3702     /* Output the stuff */
3703     while (Count) {
3704
3705         /* How many go into this line? */
3706         if ((Chunk = Count) > 16) {
3707             Chunk = 16;
3708         }
3709         Count -= Chunk;
3710
3711         /* Output one line */
3712         strcpy (Buf, "\t.byte\t");
3713         B = Buf + 7;
3714         do {
3715             B += sprintf (B, "$%02X", *Bytes++ & 0xFF);
3716             if (--Chunk) {
3717                 *B++ = ',';
3718             }
3719         } while (Chunk);
3720
3721         /* Output the line */
3722         AddCodeLine (Buf);
3723     }
3724 }
3725
3726
3727
3728 void g_zerobytes (unsigned n)
3729 /* Output n bytes of data initialized with zero */
3730 {
3731     AddCodeLine ("\t.res\t%u,$00", n);
3732 }
3733
3734
3735
3736 /*****************************************************************************/
3737 /*                          Inlined known functions                          */
3738 /*****************************************************************************/
3739
3740
3741
3742 void g_strlen (unsigned flags, unsigned long val, unsigned offs)
3743 /* Inline the strlen() function */
3744 {
3745     /* We need a label in both cases */
3746     unsigned label = GetLabel ();
3747
3748     /* Two different encodings */
3749     if (flags & CF_CONST) {
3750
3751         /* The address of the string is constant. Create the correct label name */
3752         char* lbuf = GetLabelName (flags, val, offs);
3753
3754         /* Generate the strlen code */
3755         AddCodeLine ("\tldy\t#$FF");
3756         g_defloclabel (label);
3757         AddCodeLine ("\tiny");
3758         AddCodeLine ("\tlda\t%s,y", lbuf);
3759         AddCodeLine ("\tbne\tL%04X", label);
3760         AddCodeLine ("\ttax");
3761         AddCodeLine ("\ttya");
3762
3763     } else {
3764
3765         /* Address not constant but in primary */
3766         if (FavourSize) {
3767             /* This is too much code, so call strlen instead of inlining */
3768             AddCodeLine ("\tjsr\t_strlen");
3769         } else {
3770             /* Inline the function */
3771             AddCodeLine ("\tsta\tptr1");
3772             AddCodeLine ("\tstx\tptr1+1");
3773             AddCodeLine ("\tldy\t#$FF");
3774             g_defloclabel (label);
3775             AddCodeLine ("\tiny");
3776             AddCodeLine ("\tlda\t(ptr1),y");
3777             AddCodeLine ("\tbne\tL%04X", label);
3778             AddCodeLine ("\ttax");
3779             AddCodeLine ("\ttya");
3780         }
3781     }
3782 }
3783
3784
3785