1/*****************************************************************************/
2/* */
3/* codegen.c */
4/* */
5/* 6502 code generator */
6/* */
7/* */
8/* */
9/* (C) 1998-2013, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
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#include <stdarg.h>
39
40/* common */
41#include "check.h"
42#include "cpu.h"
43#include "inttypes.h"
44#include "strbuf.h"
45#include "xmalloc.h"
46#include "xsprintf.h"
47#include "version.h"
48
49/* cc65 */
50#include "asmcode.h"
51#include "asmlabel.h"
52#include "casenode.h"
53#include "codeseg.h"
54#include "dataseg.h"
55#include "error.h"
56#include "global.h"
57#include "segments.h"
58#include "stackptr.h"
59#include "stdfunc.h"
60#include "textseg.h"
61#include "util.h"
62#include "codegen.h"
63
64
65
66/*****************************************************************************/
67/* Helpers */
68/*****************************************************************************/
69
70
71
72static void typeerror (unsigned type)
73/* Print an error message about an invalid operand type */
74{
75 /* Special handling for floats here: */
76 if ((type & CF_TYPEMASK) == CF_FLOAT) {
77 Fatal ("Floating point type is currently unsupported");
78 } else {
79 Internal ("Invalid type in CF flags: %04X, type = %u", type, type & CF_TYPEMASK);
80 }
81}
82
83
84
85static void CheckLocalOffs (unsigned Offs)
86/* Check the offset into the stack for 8bit range */
87{
88 if (Offs >= 256) {
89 /* Too many local vars */
90 Error ("Too many local variables");
91 }
92}
93
94
95
96static const char* GetLabelName (unsigned Flags, uintptr_t Label, long Offs)
97{
98 static char Buf [256]; /* Label name */
99
100 /* Create the correct label name */
101 switch (Flags & CF_ADDRMASK) {
102
103 case CF_STATIC:
104 /* Static memory cell */
105 if (Offs) {
106 xsprintf (Buf, sizeof (Buf), "%s%+ld", LocalLabelName (Label), Offs);
107 } else {
108 xsprintf (Buf, sizeof (Buf), "%s", LocalLabelName (Label));
109 }
110 break;
111
112 case CF_EXTERNAL:
113 /* External label */
114 if (Offs) {
115 xsprintf (Buf, sizeof (Buf), "_%s%+ld", (char*) Label, Offs);
116 } else {
117 xsprintf (Buf, sizeof (Buf), "_%s", (char*) Label);
118 }
119 break;
120
121 case CF_ABSOLUTE:
122 /* Absolute address */
123 xsprintf (Buf, sizeof (Buf), "$%04X", (unsigned)((Label+Offs) & 0xFFFF));
124 break;
125
126 case CF_REGVAR:
127 /* Variable in register bank */
128 xsprintf (Buf, sizeof (Buf), "regbank+%u", (unsigned)((Label+Offs) & 0xFFFF));
129 break;
130
131 default:
132 Internal ("Invalid address flags: %04X", Flags);
133 }
134
135 /* Return a pointer to the static buffer */
136 return Buf;
137}
138
139
140
141/*****************************************************************************/
142/* Pre- and postamble */
143/*****************************************************************************/
144
145
146
147void g_preamble (void)
148/* Generate the assembler code preamble */
149{
150 /* Identify the compiler version */
151 AddTextLine (";");
152 AddTextLine ("; File generated by cc65 v %s", GetVersionAsString ());
153 AddTextLine (";");
154
155 /* Insert some object file options */
156 AddTextLine ("\t.fopt\t\tcompiler,\"cc65 v %s\"",
157 GetVersionAsString ());
158
159 /* If we're producing code for some other CPU, switch the command set */
160 switch (CPU) {
161 case CPU_6502: AddTextLine ("\t.setcpu\t\t\"6502\""); break;
162 case CPU_6502X: AddTextLine ("\t.setcpu\t\t\"6502X\""); break;
163 case CPU_65SC02: AddTextLine ("\t.setcpu\t\t\"65SC02\""); break;
164 case CPU_65C02: AddTextLine ("\t.setcpu\t\t\"65C02\""); break;
165 case CPU_65816: AddTextLine ("\t.setcpu\t\t\"65816\""); break;
166 case CPU_HUC6280: AddTextLine ("\t.setcpu\t\t\"HUC6280\""); break;
167 default: Internal ("Unknown CPU: %d", CPU);
168 }
169
170 /* Use smart mode */
171 AddTextLine ("\t.smart\t\ton");
172
173 /* Allow auto import for runtime library routines */
174 AddTextLine ("\t.autoimport\ton");
175
176 /* Switch the assembler into case sensitive mode */
177 AddTextLine ("\t.case\t\ton");
178
179 /* Tell the assembler if we want to generate debug info */
180 AddTextLine ("\t.debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
181
182 /* Import zero page variables */
183 AddTextLine ("\t.importzp\tsp, sreg, regsave, regbank");
184 AddTextLine ("\t.importzp\ttmp1, tmp2, tmp3, tmp4, ptr1, ptr2, ptr3, ptr4");
185
186 /* Define long branch macros */
187 AddTextLine ("\t.macpack\tlongbranch");
188}
189
190
191
192void g_fileinfo (const char* Name, unsigned long Size, unsigned long MTime)
193/* If debug info is enabled, place a file info into the source */
194{
195 if (DebugInfo) {
196 /* We have to place this into the global text segment, so it will
197 ** appear before all .dbg line statements.
198 */
199 TS_AddLine (GS->Text, "\t.dbg\t\tfile, \"%s\", %lu, %lu", Name, Size, MTime);
200 }
201}
202
203
204
205/*****************************************************************************/
206/* Segment support */
207/*****************************************************************************/
208
209
210
211void g_userodata (void)
212/* Switch to the read only data segment */
213{
214 UseDataSeg (SEG_RODATA);
215}
216
217
218
219void g_usedata (void)
220/* Switch to the data segment */
221{
222 UseDataSeg (SEG_DATA);
223}
224
225
226
227void g_usebss (void)
228/* Switch to the bss segment */
229{
230 UseDataSeg (SEG_BSS);
231}
232
233
234
235void g_segname (segment_t Seg)
236/* Emit the name of a segment if necessary */
237{
238 /* Emit a segment directive for the data style segments */
239 DataSeg* S;
240 switch (Seg) {
241 case SEG_RODATA: S = CS->ROData; break;
242 case SEG_DATA: S = CS->Data; break;
243 case SEG_BSS: S = CS->BSS; break;
244 default: S = 0; break;
245 }
246 if (S) {
247 DS_AddLine (S, ".segment\t\"%s\"", GetSegName (Seg));
248 }
249}
250
251
252
253/*****************************************************************************/
254/* Code */
255/*****************************************************************************/
256
257
258
259unsigned sizeofarg (unsigned flags)
260/* Return the size of a function argument type that is encoded in flags */
261{
262 switch (flags & CF_TYPEMASK) {
263
264 case CF_CHAR:
265 return (flags & CF_FORCECHAR)? 1 : 2;
266
267 case CF_INT:
268 return 2;
269
270 case CF_LONG:
271 return 4;
272
273 case CF_FLOAT:
274 return 4;
275
276 default:
277 typeerror (flags);
278 /* NOTREACHED */
279 return 2;
280 }
281}
282
283
284
285int pop (unsigned flags)
286/* Pop an argument of the given size */
287{
288 return StackPtr += sizeofarg (flags);
289}
290
291
292
293int push (unsigned flags)
294/* Push an argument of the given size */
295{
296 return StackPtr -= sizeofarg (flags);
297}
298
299
300
301static unsigned MakeByteOffs (unsigned Flags, unsigned Offs)
302/* The value in Offs is an offset to an address in a/x. Make sure, an object
303** of the type given in Flags can be loaded or stored into this address by
304** adding part of the offset to the address in ax, so that the remaining
305** offset fits into an index register. Return the remaining offset.
306*/
307{
308 /* If the offset is too large for a byte register, add the high byte
309 ** of the offset to the primary. Beware: We need a special correction
310 ** if the offset in the low byte will overflow in the operation.
311 */
312 unsigned O = Offs & ~0xFFU;
313 if ((Offs & 0xFF) > 256 - sizeofarg (Flags)) {
314 /* We need to add the low byte also */
315 O += Offs & 0xFF;
316 }
317
318 /* Do the correction if we need one */
319 if (O != 0) {
320 g_inc (CF_INT | CF_CONST, O);
321 Offs -= O;
322 }
323
324 /* Return the new offset */
325 return Offs;
326}
327
328
329
330/*****************************************************************************/
331/* Functions handling local labels */
332/*****************************************************************************/
333
334
335
336void g_defcodelabel (unsigned label)
337/* Define a local code label */
338{
339 CS_AddLabel (CS->Code, LocalLabelName (label));
340}
341
342
343
344void g_defdatalabel (unsigned label)
345/* Define a local data label */
346{
347 AddDataLine ("%s:", LocalLabelName (label));
348}
349
350
351
352void g_aliasdatalabel (unsigned label, unsigned baselabel, long offs)
353/* Define label as a local alias for baselabel+offs */
354{
355 /* We need an intermediate buffer here since LocalLabelName uses a
356 ** static buffer which changes with each call.
357 */
358 StrBuf L = AUTO_STRBUF_INITIALIZER;
359 SB_AppendStr (&L, LocalLabelName (label));
360 SB_Terminate (&L);
361 AddDataLine ("%s\t:=\t%s+%ld",
362 SB_GetConstBuf (&L),
363 LocalLabelName (baselabel),
364 offs);
365 SB_Done (&L);
366}
367
368
369
370/*****************************************************************************/
371/* Functions handling global labels */
372/*****************************************************************************/
373
374
375
376void g_defgloblabel (const char* Name)
377/* Define a global label with the given name */
378{
379 /* Global labels are always data labels */
380 AddDataLine ("_%s:", Name);
381}
382
383
384
385void g_defexport (const char* Name, int ZP)
386/* Export the given label */
387{
388 if (ZP) {
389 AddTextLine ("\t.exportzp\t_%s", Name);
390 } else {
391 AddTextLine ("\t.export\t\t_%s", Name);
392 }
393}
394
395
396
397void g_defimport (const char* Name, int ZP)
398/* Import the given label */
399{
400 if (ZP) {
401 AddTextLine ("\t.importzp\t_%s", Name);
402 } else {
403 AddTextLine ("\t.import\t\t_%s", Name);
404 }
405}
406
407
408
409void g_importstartup (void)
410/* Forced import of the startup module */
411{
412 AddTextLine ("\t.forceimport\t__STARTUP__");
413}
414
415
416
417void g_importmainargs (void)
418/* Forced import of a special symbol that handles arguments to main */
419{
420 AddTextLine ("\t.forceimport\tinitmainargs");
421}
422
423
424
425/*****************************************************************************/
426/* Function entry and exit */
427/*****************************************************************************/
428
429
430
431/* Remember the argument size of a function. The variable is set by g_enter
432** and used by g_leave. If the function gets its argument size by the caller
433** (variable param list or function without prototype), g_enter will set the
434** value to -1.
435*/
436static int funcargs;
437
438
439void g_enter (unsigned flags, unsigned argsize)
440/* Function prologue */
441{
442 if ((flags & CF_FIXARGC) != 0) {
443 /* Just remember the argument size for the leave */
444 funcargs = argsize;
445 } else {
446 funcargs = -1;
447 AddCodeLine ("jsr enter");
448 }
449}
450
451
452
453void g_leave (void)
454/* Function epilogue */
455{
456 /* How many bytes of locals do we have to drop? */
457 unsigned ToDrop = (unsigned) -StackPtr;
458
459 /* If we didn't have a variable argument list, don't call leave */
460 if (funcargs >= 0) {
461
462 /* Drop stackframe if needed */
463 g_drop (ToDrop + funcargs);
464
465 } else if (StackPtr != 0) {
466
467 /* We've a stack frame to drop */
468 if (ToDrop > 255) {
469 g_drop (ToDrop); /* Inlines the code */
470 AddCodeLine ("jsr leave");
471 } else {
472 AddCodeLine ("ldy #$%02X", ToDrop);
473 AddCodeLine ("jsr leavey");
474 }
475
476 } else {
477
478 /* Nothing to drop */
479 AddCodeLine ("jsr leave");
480
481 }
482
483 /* Add the final rts */
484 AddCodeLine ("rts");
485}
486
487
488
489/*****************************************************************************/
490/* Register variables */
491/*****************************************************************************/
492
493
494
495void g_swap_regvars (int StackOffs, int RegOffs, unsigned Bytes)
496/* Swap a register variable with a location on the stack */
497{
498 /* Calculate the actual stack offset and check it */
499 StackOffs -= StackPtr;
500 CheckLocalOffs (StackOffs);
501
502 /* Generate code */
503 AddCodeLine ("ldy #$%02X", StackOffs & 0xFF);
504 if (Bytes == 1) {
505
506 if (IS_Get (&CodeSizeFactor) < 165) {
507 AddCodeLine ("ldx #$%02X", RegOffs & 0xFF);
508 AddCodeLine ("jsr regswap1");
509 } else {
510 AddCodeLine ("lda (sp),y");
511 AddCodeLine ("ldx regbank%+d", RegOffs);
512 AddCodeLine ("sta regbank%+d", RegOffs);
513 AddCodeLine ("txa");
514 AddCodeLine ("sta (sp),y");
515 }
516
517 } else if (Bytes == 2) {
518
519 AddCodeLine ("ldx #$%02X", RegOffs & 0xFF);
520 AddCodeLine ("jsr regswap2");
521
522 } else {
523
524 AddCodeLine ("ldx #$%02X", RegOffs & 0xFF);
525 AddCodeLine ("lda #$%02X", Bytes & 0xFF);
526 AddCodeLine ("jsr regswap");
527 }
528}
529
530
531
532void g_save_regvars (int RegOffs, unsigned Bytes)
533/* Save register variables */
534{
535 /* Don't loop for up to two bytes */
536 if (Bytes == 1) {
537
538 AddCodeLine ("lda regbank%+d", RegOffs);
539 AddCodeLine ("jsr pusha");
540
541 } else if (Bytes == 2) {
542
543 AddCodeLine ("lda regbank%+d", RegOffs);
544 AddCodeLine ("ldx regbank%+d", RegOffs+1);
545 AddCodeLine ("jsr pushax");
546
547 } else {
548
549 /* More than two bytes - loop */
550 unsigned Label = GetLocalLabel ();
551 g_space (Bytes);
552 AddCodeLine ("ldy #$%02X", (unsigned char) (Bytes - 1));
553 AddCodeLine ("ldx #$%02X", (unsigned char) Bytes);
554 g_defcodelabel (Label);
555 AddCodeLine ("lda regbank%+d,x", RegOffs-1);
556 AddCodeLine ("sta (sp),y");
557 AddCodeLine ("dey");
558 AddCodeLine ("dex");
559 AddCodeLine ("bne %s", LocalLabelName (Label));
560
561 }
562
563 /* We pushed stuff, correct the stack pointer */
564 StackPtr -= Bytes;
565}
566
567
568
569void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
570/* Restore register variables */
571{
572 /* Calculate the actual stack offset and check it */
573 StackOffs -= StackPtr;
574 CheckLocalOffs (StackOffs);
575
576 /* Don't loop for up to two bytes */
577 if (Bytes == 1) {
578
579 AddCodeLine ("ldy #$%02X", StackOffs);
580 AddCodeLine ("lda (sp),y");
581 AddCodeLine ("sta regbank%+d", RegOffs);
582
583 } else if (Bytes == 2) {
584
585 AddCodeLine ("ldy #$%02X", StackOffs);
586 AddCodeLine ("lda (sp),y");
587 AddCodeLine ("sta regbank%+d", RegOffs);
588 AddCodeLine ("iny");
589 AddCodeLine ("lda (sp),y");
590 AddCodeLine ("sta regbank%+d", RegOffs+1);
591
592 } else if (Bytes == 3 && IS_Get (&CodeSizeFactor) >= 133) {
593
594 AddCodeLine ("ldy #$%02X", StackOffs);
595 AddCodeLine ("lda (sp),y");
596 AddCodeLine ("sta regbank%+d", RegOffs);
597 AddCodeLine ("iny");
598 AddCodeLine ("lda (sp),y");
599 AddCodeLine ("sta regbank%+d", RegOffs+1);
600 AddCodeLine ("iny");
601 AddCodeLine ("lda (sp),y");
602 AddCodeLine ("sta regbank%+d", RegOffs+2);
603
604 } else if (StackOffs <= RegOffs) {
605
606 /* More bytes, but the relation between the register offset in the
607 ** register bank and the stack offset allows us to generate short
608 ** code that uses just one index register.
609 */
610 unsigned Label = GetLocalLabel ();
611 AddCodeLine ("ldy #$%02X", StackOffs);
612 g_defcodelabel (Label);
613 AddCodeLine ("lda (sp),y");
614 AddCodeLine ("sta regbank%+d,y", RegOffs - StackOffs);
615 AddCodeLine ("iny");
616 AddCodeLine ("cpy #$%02X", StackOffs + Bytes);
617 AddCodeLine ("bne %s", LocalLabelName (Label));
618
619 } else {
620
621 /* OK, this is the generic code. We need to save X because the
622 ** caller will only save A.
623 */
624 unsigned Label = GetLocalLabel ();
625 AddCodeLine ("stx tmp1");
626 AddCodeLine ("ldy #$%02X", (unsigned char) (StackOffs + Bytes - 1));
627 AddCodeLine ("ldx #$%02X", (unsigned char) (Bytes - 1));
628 g_defcodelabel (Label);
629 AddCodeLine ("lda (sp),y");
630 AddCodeLine ("sta regbank%+d,x", RegOffs);
631 AddCodeLine ("dey");
632 AddCodeLine ("dex");
633 AddCodeLine ("bpl %s", LocalLabelName (Label));
634 AddCodeLine ("ldx tmp1");
635
636 }
637}
638
639
640
641/*****************************************************************************/
642/* Fetching memory cells */
643/*****************************************************************************/
644
645
646
647void g_getimmed (unsigned Flags, unsigned long Val, long Offs)
648/* Load a constant into the primary register */
649{
650 unsigned char B1, B2, B3, B4;
651 unsigned Done;
652
653
654 if ((Flags & CF_CONST) != 0) {
655
656 /* Numeric constant */
657 switch (Flags & CF_TYPEMASK) {
658
659 case CF_CHAR:
660 if ((Flags & CF_FORCECHAR) != 0) {
661 AddCodeLine ("lda #$%02X", (unsigned char) Val);
662 break;
663 }
664 /* FALL THROUGH */
665 case CF_INT:
666 AddCodeLine ("ldx #$%02X", (unsigned char) (Val >> 8));
667 AddCodeLine ("lda #$%02X", (unsigned char) Val);
668 break;
669
670 case CF_LONG:
671 /* Split the value into 4 bytes */
672 B1 = (unsigned char) (Val >> 0);
673 B2 = (unsigned char) (Val >> 8);
674 B3 = (unsigned char) (Val >> 16);
675 B4 = (unsigned char) (Val >> 24);
676
677 /* Remember which bytes are done */
678 Done = 0;
679
680 /* Load the value */
681 AddCodeLine ("ldx #$%02X", B2);
682 Done |= 0x02;
683 if (B2 == B3) {
684 AddCodeLine ("stx sreg");
685 Done |= 0x04;
686 }
687 if (B2 == B4) {
688 AddCodeLine ("stx sreg+1");
689 Done |= 0x08;
690 }
691 if ((Done & 0x04) == 0 && B1 != B3) {
692 AddCodeLine ("lda #$%02X", B3);
693 AddCodeLine ("sta sreg");
694 Done |= 0x04;
695 }
696 if ((Done & 0x08) == 0 && B1 != B4) {
697 AddCodeLine ("lda #$%02X", B4);
698 AddCodeLine ("sta sreg+1");
699 Done |= 0x08;
700 }
701 AddCodeLine ("lda #$%02X", B1);
702 Done |= 0x01;
703 if ((Done & 0x04) == 0) {
704 CHECK (B1 == B3);
705 AddCodeLine ("sta sreg");
706 }
707 if ((Done & 0x08) == 0) {
708 CHECK (B1 == B4);
709 AddCodeLine ("sta sreg+1");
710 }
711 break;
712
713 default:
714 typeerror (Flags);
715 break;
716
717 }
718
719 } else {
720
721 /* Some sort of label */
722 const char* Label = GetLabelName (Flags, Val, Offs);
723
724 /* Load the address into the primary */
725 AddCodeLine ("lda #<(%s)", Label);
726 AddCodeLine ("ldx #>(%s)", Label);
727
728 }
729}
730
731
732
733void g_getstatic (unsigned flags, uintptr_t label, long offs)
734/* Fetch an static memory cell into the primary register */
735{
736 /* Create the correct label name */
737 const char* lbuf = GetLabelName (flags, label, offs);
738
739 /* Check the size and generate the correct load operation */
740 switch (flags & CF_TYPEMASK) {
741
742 case CF_CHAR:
743 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
744 AddCodeLine ("lda %s", lbuf); /* load A from the label */
745 } else {
746 AddCodeLine ("ldx #$00");
747 AddCodeLine ("lda %s", lbuf); /* load A from the label */
748 if (!(flags & CF_UNSIGNED)) {
749 /* Must sign extend */
750 unsigned L = GetLocalLabel ();
751 AddCodeLine ("bpl %s", LocalLabelName (L));
752 AddCodeLine ("dex");
753 g_defcodelabel (L);
754 }
755 }
756 break;
757
758 case CF_INT:
759 AddCodeLine ("lda %s", lbuf);
760 if (flags & CF_TEST) {
761 AddCodeLine ("ora %s+1", lbuf);
762 } else {
763 AddCodeLine ("ldx %s+1", lbuf);
764 }
765 break;
766
767 case CF_LONG:
768 if (flags & CF_TEST) {
769 AddCodeLine ("lda %s+3", lbuf);
770 AddCodeLine ("ora %s+2", lbuf);
771 AddCodeLine ("ora %s+1", lbuf);
772 AddCodeLine ("ora %s+0", lbuf);
773 } else {
774 AddCodeLine ("lda %s+3", lbuf);
775 AddCodeLine ("sta sreg+1");
776 AddCodeLine ("lda %s+2", lbuf);
777 AddCodeLine ("sta sreg");
778 AddCodeLine ("ldx %s+1", lbuf);
779 AddCodeLine ("lda %s", lbuf);
780 }
781 break;
782
783 default:
784 typeerror (flags);
785
786 }
787}
788
789
790
791void g_getlocal (unsigned Flags, int Offs)
792/* Fetch specified local object (local var). */
793{
794 Offs -= StackPtr;
795 switch (Flags & CF_TYPEMASK) {
796
797 case CF_CHAR:
798 CheckLocalOffs (Offs);
799 if ((Flags & CF_FORCECHAR) || (Flags & CF_TEST)) {
800 AddCodeLine ("ldy #$%02X", Offs);
801 AddCodeLine ("lda (sp),y");
802 } else {
803 AddCodeLine ("ldy #$%02X", Offs);
804 AddCodeLine ("ldx #$00");
805 AddCodeLine ("lda (sp),y");
806 if ((Flags & CF_UNSIGNED) == 0) {
807 unsigned L = GetLocalLabel();
808 AddCodeLine ("bpl %s", LocalLabelName (L));
809 AddCodeLine ("dex");
810 g_defcodelabel (L);
811 }
812 }
813 break;
814
815 case CF_INT:
816 CheckLocalOffs (Offs + 1);
817 AddCodeLine ("ldy #$%02X", (unsigned char) (Offs+1));
818 if (Flags & CF_TEST) {
819 AddCodeLine ("lda (sp),y");
820 AddCodeLine ("dey");
821 AddCodeLine ("ora (sp),y");
822 } else {
823 AddCodeLine ("jsr ldaxysp");
824 }
825 break;
826
827 case CF_LONG:
828 CheckLocalOffs (Offs + 3);
829 AddCodeLine ("ldy #$%02X", (unsigned char) (Offs+3));
830 AddCodeLine ("jsr ldeaxysp");
831 if (Flags & CF_TEST) {
832 g_test (Flags);
833 }
834 break;
835
836 default:
837 typeerror (Flags);
838 }
839}
840
841
842
843void g_getind (unsigned Flags, unsigned Offs)
844/* Fetch the specified object type indirect through the primary register
845** into the primary register
846*/
847{
848 /* If the offset is greater than 255, add the part that is > 255 to
849 ** the primary. This way we get an easy addition and use the low byte
850 ** as the offset
851 */
852 Offs = MakeByteOffs (Flags, Offs);
853
854 /* Handle the indirect fetch */
855 switch (Flags & CF_TYPEMASK) {
856
857 case CF_CHAR:
858 /* Character sized */
859 AddCodeLine ("ldy #$%02X", Offs);
860 if (Flags & CF_UNSIGNED) {
861 AddCodeLine ("jsr ldauidx");
862 } else {
863 AddCodeLine ("jsr ldaidx");
864 }
865 break;
866
867 case CF_INT:
868 if (Flags & CF_TEST) {
869 AddCodeLine ("ldy #$%02X", Offs);
870 AddCodeLine ("sta ptr1");
871 AddCodeLine ("stx ptr1+1");
872 AddCodeLine ("lda (ptr1),y");
873 AddCodeLine ("iny");
874 AddCodeLine ("ora (ptr1),y");
875 } else {
876 AddCodeLine ("ldy #$%02X", Offs+1);
877 AddCodeLine ("jsr ldaxidx");
878 }
879 break;
880
881 case CF_LONG:
882 AddCodeLine ("ldy #$%02X", Offs+3);
883 AddCodeLine ("jsr ldeaxidx");
884 if (Flags & CF_TEST) {
885 g_test (Flags);
886 }
887 break;
888
889 default:
890 typeerror (Flags);
891
892 }
893}
894
895
896
897void g_leasp (int Offs)
898/* Fetch the address of the specified symbol into the primary register */
899{
900 unsigned char Lo, Hi;
901
902 /* Calculate the offset relative to sp */
903 Offs -= StackPtr;
904
905 /* Get low and high byte */
906 Lo = (unsigned char) Offs;
907 Hi = (unsigned char) (Offs >> 8);
908
909 /* Generate code */
910 if (Lo == 0) {
911 if (Hi <= 3) {
912 AddCodeLine ("lda sp");
913 AddCodeLine ("ldx sp+1");
914 while (Hi--) {
915 AddCodeLine ("inx");
916 }
917 } else {
918 AddCodeLine ("lda sp+1");
919 AddCodeLine ("clc");
920 AddCodeLine ("adc #$%02X", Hi);
921 AddCodeLine ("tax");
922 AddCodeLine ("lda sp");
923 }
924 } else if (Hi == 0) {
925 /* 8 bit offset */
926 if (IS_Get (&CodeSizeFactor) < 200) {
927 /* 8 bit offset with subroutine call */
928 AddCodeLine ("lda #$%02X", Lo);
929 AddCodeLine ("jsr leaa0sp");
930 } else {
931 /* 8 bit offset inlined */
932 unsigned L = GetLocalLabel ();
933 AddCodeLine ("lda sp");
934 AddCodeLine ("ldx sp+1");
935 AddCodeLine ("clc");
936 AddCodeLine ("adc #$%02X", Lo);
937 AddCodeLine ("bcc %s", LocalLabelName (L));
938 AddCodeLine ("inx");
939 g_defcodelabel (L);
940 }
941 } else if (IS_Get (&CodeSizeFactor) < 170) {
942 /* Full 16 bit offset with subroutine call */
943 AddCodeLine ("lda #$%02X", Lo);
944 AddCodeLine ("ldx #$%02X", Hi);
945 AddCodeLine ("jsr leaaxsp");
946 } else {
947 /* Full 16 bit offset inlined */
948 AddCodeLine ("lda sp");
949 AddCodeLine ("clc");
950 AddCodeLine ("adc #$%02X", Lo);
951 AddCodeLine ("pha");
952 AddCodeLine ("lda sp+1");
953 AddCodeLine ("adc #$%02X", Hi);
954 AddCodeLine ("tax");
955 AddCodeLine ("pla");
956 }
957}
958
959
960
961void g_leavariadic (int Offs)
962/* Fetch the address of a parameter in a variadic function into the primary
963** register
964*/
965{
966 unsigned ArgSizeOffs;
967
968 /* Calculate the offset relative to sp */
969 Offs -= StackPtr;
970
971 /* Get the offset of the parameter which is stored at sp+0 on function
972 ** entry and check if this offset is reachable with a byte offset.
973 */
974 CHECK (StackPtr <= 0);
975 ArgSizeOffs = -StackPtr;
976 CheckLocalOffs (ArgSizeOffs);
977
978 /* Get the size of all parameters. */
979 AddCodeLine ("ldy #$%02X", ArgSizeOffs);
980 AddCodeLine ("lda (sp),y");
981
982 /* Add the value of the stackpointer */
983 if (IS_Get (&CodeSizeFactor) > 250) {
984 unsigned L = GetLocalLabel();
985 AddCodeLine ("ldx sp+1");
986 AddCodeLine ("clc");
987 AddCodeLine ("adc sp");
988 AddCodeLine ("bcc %s", LocalLabelName (L));
989 AddCodeLine ("inx");
990 g_defcodelabel (L);
991 } else {
992 AddCodeLine ("ldx #$00");
993 AddCodeLine ("jsr leaaxsp");
994 }
995
996 /* Add the offset to the primary */
997 if (Offs > 0) {
998 g_inc (CF_INT | CF_CONST, Offs);
999 } else if (Offs < 0) {
1000 g_dec (CF_INT | CF_CONST, -Offs);
1001 }
1002}
1003
1004
1005
1006/*****************************************************************************/
1007/* Store into memory */
1008/*****************************************************************************/
1009
1010
1011
1012void g_putstatic (unsigned flags, uintptr_t label, long offs)
1013/* Store the primary register into the specified static memory cell */
1014{
1015 /* Create the correct label name */
1016 const char* lbuf = GetLabelName (flags, label, offs);
1017
1018 /* Check the size and generate the correct store operation */
1019 switch (flags & CF_TYPEMASK) {
1020
1021 case CF_CHAR:
1022 AddCodeLine ("sta %s", lbuf);
1023 break;
1024
1025 case CF_INT:
1026 AddCodeLine ("sta %s", lbuf);
1027 AddCodeLine ("stx %s+1", lbuf);
1028 break;
1029
1030 case CF_LONG:
1031 AddCodeLine ("sta %s", lbuf);
1032 AddCodeLine ("stx %s+1", lbuf);
1033 AddCodeLine ("ldy sreg");
1034 AddCodeLine ("sty %s+2", lbuf);
1035 AddCodeLine ("ldy sreg+1");
1036 AddCodeLine ("sty %s+3", lbuf);
1037 break;
1038
1039 default:
1040 typeerror (flags);
1041
1042 }
1043}
1044
1045
1046
1047void g_putlocal (unsigned Flags, int Offs, long Val)
1048/* Put data into local object. */
1049{
1050 Offs -= StackPtr;
1051 CheckLocalOffs (Offs);
1052 switch (Flags & CF_TYPEMASK) {
1053
1054 case CF_CHAR:
1055 if (Flags & CF_CONST) {
1056 AddCodeLine ("lda #$%02X", (unsigned char) Val);
1057 }
1058 AddCodeLine ("ldy #$%02X", Offs);
1059 AddCodeLine ("sta (sp),y");
1060 break;
1061
1062 case CF_INT:
1063 if (Flags & CF_CONST) {
1064 AddCodeLine ("ldy #$%02X", Offs+1);
1065 AddCodeLine ("lda #$%02X", (unsigned char) (Val >> 8));
1066 AddCodeLine ("sta (sp),y");
1067 if ((Flags & CF_NOKEEP) == 0) {
1068 /* Place high byte into X */
1069 AddCodeLine ("tax");
1070 }
1071 if ((Val & 0xFF) == Offs+1) {
1072 /* The value we need is already in Y */
1073 AddCodeLine ("tya");
1074 AddCodeLine ("dey");
1075 } else {
1076 AddCodeLine ("dey");
1077 AddCodeLine ("lda #$%02X", (unsigned char) Val);
1078 }
1079 AddCodeLine ("sta (sp),y");
1080 } else {
1081 AddCodeLine ("ldy #$%02X", Offs);
1082 if ((Flags & CF_NOKEEP) == 0 || IS_Get (&CodeSizeFactor) < 160) {
1083 AddCodeLine ("jsr staxysp");
1084 } else {
1085 AddCodeLine ("sta (sp),y");
1086 AddCodeLine ("iny");
1087 AddCodeLine ("txa");
1088 AddCodeLine ("sta (sp),y");
1089 }
1090 }
1091 break;
1092
1093 case CF_LONG:
1094 if (Flags & CF_CONST) {
1095 g_getimmed (Flags, Val, 0);
1096 }
1097 AddCodeLine ("ldy #$%02X", Offs);
1098 AddCodeLine ("jsr steaxysp");
1099 break;
1100
1101 default:
1102 typeerror (Flags);
1103
1104 }
1105}
1106
1107
1108
1109void g_putind (unsigned Flags, unsigned Offs)
1110/* Store the specified object type in the primary register at the address
1111** on the top of the stack
1112*/
1113{
1114 /* We can handle offsets below $100 directly, larger offsets must be added
1115 ** to the address. Since a/x is in use, best code is achieved by adding
1116 ** just the high byte. Be sure to check if the low byte will overflow while
1117 ** while storing.
1118 */
1119 if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
1120
1121 /* Overflow - we need to add the low byte also */
1122 AddCodeLine ("ldy #$00");
1123 AddCodeLine ("clc");
1124 AddCodeLine ("pha");
1125 AddCodeLine ("lda #$%02X", Offs & 0xFF);
1126 AddCodeLine ("adc (sp),y");
1127 AddCodeLine ("sta (sp),y");
1128 AddCodeLine ("iny");
1129 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1130 AddCodeLine ("adc (sp),y");
1131 AddCodeLine ("sta (sp),y");
1132 AddCodeLine ("pla");
1133
1134 /* Complete address is on stack, new offset is zero */
1135 Offs = 0;
1136
1137 } else if ((Offs & 0xFF00) != 0) {
1138
1139 /* We can just add the high byte */
1140 AddCodeLine ("ldy #$01");
1141 AddCodeLine ("clc");
1142 AddCodeLine ("pha");
1143 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1144 AddCodeLine ("adc (sp),y");
1145 AddCodeLine ("sta (sp),y");
1146 AddCodeLine ("pla");
1147
1148 /* Offset is now just the low byte */
1149 Offs &= 0x00FF;
1150 }
1151
1152 /* Check the size and determine operation */
1153 AddCodeLine ("ldy #$%02X", Offs);
1154 switch (Flags & CF_TYPEMASK) {
1155
1156 case CF_CHAR:
1157 AddCodeLine ("jsr staspidx");
1158 break;
1159
1160 case CF_INT:
1161 AddCodeLine ("jsr staxspidx");
1162 break;
1163
1164 case CF_LONG:
1165 AddCodeLine ("jsr steaxspidx");
1166 break;
1167
1168 default:
1169 typeerror (Flags);
1170
1171 }
1172
1173 /* Pop the argument which is always a pointer */
1174 pop (CF_PTR);
1175}
1176
1177
1178
1179/*****************************************************************************/
1180/* type conversion and similiar stuff */
1181/*****************************************************************************/
1182
1183
1184
1185void g_toslong (unsigned flags)
1186/* Make sure, the value on TOS is a long. Convert if necessary */
1187{
1188 switch (flags & CF_TYPEMASK) {
1189
1190 case CF_CHAR:
1191 case CF_INT:
1192 if (flags & CF_UNSIGNED) {
1193 AddCodeLine ("jsr tosulong");
1194 } else {
1195 AddCodeLine ("jsr toslong");
1196 }
1197 push (CF_INT);
1198 break;
1199
1200 case CF_LONG:
1201 break;
1202
1203 default:
1204 typeerror (flags);
1205 }
1206}
1207
1208
1209
1210void g_tosint (unsigned flags)
1211/* Make sure, the value on TOS is an int. Convert if necessary */
1212{
1213 switch (flags & CF_TYPEMASK) {
1214
1215 case CF_CHAR:
1216 case CF_INT:
1217 break;
1218
1219 case CF_LONG:
1220 AddCodeLine ("jsr tosint");
1221 pop (CF_INT);
1222 break;
1223
1224 default:
1225 typeerror (flags);
1226 }
1227}
1228
1229
1230
1231static void g_regchar (unsigned Flags)
1232/* Make sure, the value in the primary register is in the range of char. Truncate if necessary */
1233{
1234 unsigned L;
1235
1236 AddCodeLine ("ldx #$00");
1237
1238 if ((Flags & CF_UNSIGNED) == 0) {
1239 /* Sign extend */
1240 L = GetLocalLabel();
1241 AddCodeLine ("cmp #$80");
1242 AddCodeLine ("bcc %s", LocalLabelName (L));
1243 AddCodeLine ("dex");
1244 g_defcodelabel (L);
1245 }
1246}
1247
1248
1249
1250void g_regint (unsigned Flags)
1251/* Make sure, the value in the primary register an int. Convert if necessary */
1252{
1253 switch (Flags & CF_TYPEMASK) {
1254
1255 case CF_CHAR:
1256 if (Flags & CF_FORCECHAR) {
1257 /* Conversion is from char */
1258 g_regchar (Flags);
1259 }
1260 /* FALLTHROUGH */
1261
1262 case CF_INT:
1263 case CF_LONG:
1264 break;
1265
1266 default:
1267 typeerror (Flags);
1268 }
1269}
1270
1271
1272
1273void g_reglong (unsigned Flags)
1274/* Make sure, the value in the primary register a long. Convert if necessary */
1275{
1276 switch (Flags & CF_TYPEMASK) {
1277
1278 case CF_CHAR:
1279 if (Flags & CF_FORCECHAR) {
1280 /* Conversion is from char */
1281 if (Flags & CF_UNSIGNED) {
1282 if (IS_Get (&CodeSizeFactor) >= 200) {
1283 AddCodeLine ("ldx #$00");
1284 AddCodeLine ("stx sreg");
1285 AddCodeLine ("stx sreg+1");
1286 } else {
1287 AddCodeLine ("jsr aulong");
1288 }
1289 } else {
1290 if (IS_Get (&CodeSizeFactor) >= 366) {
1291 g_regchar (Flags);
1292 AddCodeLine ("stx sreg");
1293 AddCodeLine ("stx sreg+1");
1294 } else {
1295 AddCodeLine ("jsr along");
1296 }
1297 }
1298 }
1299 /* FALLTHROUGH */
1300
1301 case CF_INT:
1302 if (Flags & CF_UNSIGNED) {
1303 if (IS_Get (&CodeSizeFactor) >= 200) {
1304 AddCodeLine ("ldy #$00");
1305 AddCodeLine ("sty sreg");
1306 AddCodeLine ("sty sreg+1");
1307 } else {
1308 AddCodeLine ("jsr axulong");
1309 }
1310 } else {
1311 AddCodeLine ("jsr axlong");
1312 }
1313 break;
1314
1315 case CF_LONG:
1316 break;
1317
1318 default:
1319 typeerror (Flags);
1320 }
1321}
1322
1323
1324
1325unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1326/* Adjust the integer operands before doing a binary operation. lhs is a flags
1327** value, that corresponds to the value on TOS, rhs corresponds to the value
1328** in (e)ax. The return value is the the flags value for the resulting type.
1329*/
1330{
1331 unsigned ltype, rtype;
1332 unsigned result;
1333
1334 /* Get the type spec from the flags */
1335 ltype = lhs & CF_TYPEMASK;
1336 rtype = rhs & CF_TYPEMASK;
1337
1338 /* Check if a conversion is needed */
1339 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1340 /* We must promote the primary register to long */
1341 g_reglong (rhs);
1342 /* Get the new rhs type */
1343 rhs = (rhs & ~CF_TYPEMASK) | CF_LONG;
1344 rtype = CF_LONG;
1345 } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1346 /* We must promote the lhs to long */
1347 if (lhs & CF_REG) {
1348 g_reglong (lhs);
1349 } else {
1350 g_toslong (lhs);
1351 }
1352 /* Get the new rhs type */
1353 lhs = (lhs & ~CF_TYPEMASK) | CF_LONG;
1354 ltype = CF_LONG;
1355 }
1356
1357 /* Determine the result type for the operation:
1358 ** - The result is const if both operands are const.
1359 ** - The result is unsigned if one of the operands is unsigned.
1360 ** - The result is long if one of the operands is long.
1361 ** - Otherwise the result is int sized.
1362 */
1363 result = (lhs & CF_CONST) & (rhs & CF_CONST);
1364 result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1365 if (rtype == CF_LONG || ltype == CF_LONG) {
1366 result |= CF_LONG;
1367 } else {
1368 result |= CF_INT;
1369 }
1370 return result;
1371}
1372
1373
1374
1375unsigned g_typecast (unsigned lhs, unsigned rhs)
1376/* Cast the value in the primary register to the operand size that is flagged
1377** by the lhs value. Return the result value.
1378*/
1379{
1380 /* Check if a conversion is needed */
1381 if ((rhs & CF_CONST) == 0) {
1382 switch (lhs & CF_TYPEMASK) {
1383
1384 case CF_LONG:
1385 /* We must promote the primary register to long */
1386 g_reglong (rhs);
1387 break;
1388
1389 case CF_INT:
1390 /* We must promote the primary register to int */
1391 g_regint (rhs);
1392 break;
1393
1394 case CF_CHAR:
1395 /* We must truncate the primary register to char */
1396 g_regchar (lhs);
1397 break;
1398
1399 default:
1400 typeerror (lhs);
1401 }
1402 }
1403
1404 /* Do not need any other action. If the left type is int, and the primary
1405 ** register is long, it will be automagically truncated. If the right hand
1406 ** side is const, it is not located in the primary register and handled by
1407 ** the expression parser code.
1408 */
1409
1410 /* Result is const if the right hand side was const */
1411 lhs |= (rhs & CF_CONST);
1412
1413 /* The resulting type is that of the left hand side (that's why you called
1414 ** this function :-)
1415 */
1416 return lhs;
1417}
1418
1419
1420
1421void g_scale (unsigned flags, long val)
1422/* Scale the value in the primary register by the given value. If val is positive,
1423** scale up, is val is negative, scale down. This function is used to scale
1424** the operands or results of pointer arithmetic by the size of the type, the
1425** pointer points to.
1426*/
1427{
1428 int p2;
1429
1430 /* Value may not be zero */
1431 if (val == 0) {
1432 Internal ("Data type has no size");
1433 } else if (val > 0) {
1434
1435 /* Scale up */
1436 if ((p2 = PowerOf2 (val)) > 0 && p2 <= 4) {
1437
1438 /* Factor is 2, 4, 8 and 16, use special function */
1439 switch (flags & CF_TYPEMASK) {
1440
1441 case CF_CHAR:
1442 if (flags & CF_FORCECHAR) {
1443 while (p2--) {
1444 AddCodeLine ("asl a");
1445 }
1446 break;
1447 }
1448 /* FALLTHROUGH */
1449
1450 case CF_INT:
1451 if (flags & CF_UNSIGNED) {
1452 AddCodeLine ("jsr shlax%d", p2);
1453 } else {
1454 AddCodeLine ("jsr aslax%d", p2);
1455 }
1456 break;
1457
1458 case CF_LONG:
1459 if (flags & CF_UNSIGNED) {
1460 AddCodeLine ("jsr shleax%d", p2);
1461 } else {
1462 AddCodeLine ("jsr asleax%d", p2);
1463 }
1464 break;
1465
1466 default:
1467 typeerror (flags);
1468
1469 }
1470
1471 } else if (val != 1) {
1472
1473 /* Use a multiplication instead */
1474 g_mul (flags | CF_CONST, val);
1475
1476 }
1477
1478 } else {
1479
1480 /* Scale down */
1481 val = -val;
1482 if ((p2 = PowerOf2 (val)) > 0 && p2 <= 4) {
1483
1484 /* Factor is 2, 4, 8 and 16 use special function */
1485 switch (flags & CF_TYPEMASK) {
1486
1487 case CF_CHAR:
1488 if (flags & CF_FORCECHAR) {
1489 if (flags & CF_UNSIGNED) {
1490 while (p2--) {
1491 AddCodeLine ("lsr a");
1492 }
1493 break;
1494 } else if (p2 <= 2) {
1495 AddCodeLine ("cmp #$80");
1496 AddCodeLine ("ror a");
1497 break;
1498 }
1499 }
1500 /* FALLTHROUGH */
1501
1502 case CF_INT:
1503 if (flags & CF_UNSIGNED) {
1504 AddCodeLine ("jsr lsrax%d", p2);
1505 } else {
1506 AddCodeLine ("jsr asrax%d", p2);
1507 }
1508 break;
1509
1510 case CF_LONG:
1511 if (flags & CF_UNSIGNED) {
1512 AddCodeLine ("jsr lsreax%d", p2);
1513 } else {
1514 AddCodeLine ("jsr asreax%d", p2);
1515 }
1516 break;
1517
1518 default:
1519 typeerror (flags);
1520
1521 }
1522
1523 } else if (val != 1) {
1524
1525 /* Use a division instead */
1526 g_div (flags | CF_CONST, val);
1527
1528 }
1529 }
1530}
1531
1532
1533
1534/*****************************************************************************/
1535/* Adds and subs of variables fix a fixed address */
1536/*****************************************************************************/
1537
1538
1539
1540void g_addlocal (unsigned flags, int offs)
1541/* Add a local variable to ax */
1542{
1543 unsigned L;
1544
1545 /* Correct the offset and check it */
1546 offs -= StackPtr;
1547 CheckLocalOffs (offs);
1548
1549 switch (flags & CF_TYPEMASK) {
1550
1551 case CF_CHAR:
1552 L = GetLocalLabel();
1553 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1554 AddCodeLine ("clc");
1555 AddCodeLine ("adc (sp),y");
1556 AddCodeLine ("bcc %s", LocalLabelName (L));
1557 AddCodeLine ("inx");
1558 g_defcodelabel (L);
1559 break;
1560
1561 case CF_INT:
1562 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1563 AddCodeLine ("clc");
1564 AddCodeLine ("adc (sp),y");
1565 AddCodeLine ("pha");
1566 AddCodeLine ("txa");
1567 AddCodeLine ("iny");
1568 AddCodeLine ("adc (sp),y");
1569 AddCodeLine ("tax");
1570 AddCodeLine ("pla");
1571 break;
1572
1573 case CF_LONG:
1574 /* Do it the old way */
1575 g_push (flags, 0);
1576 g_getlocal (flags, offs);
1577 g_add (flags, 0);
1578 break;
1579
1580 default:
1581 typeerror (flags);
1582
1583 }
1584}
1585
1586
1587
1588void g_addstatic (unsigned flags, uintptr_t label, long offs)
1589/* Add a static variable to ax */
1590{
1591 unsigned L;
1592
1593 /* Create the correct label name */
1594 const char* lbuf = GetLabelName (flags, label, offs);
1595
1596 switch (flags & CF_TYPEMASK) {
1597
1598 case CF_CHAR:
1599 L = GetLocalLabel();
1600 AddCodeLine ("clc");
1601 AddCodeLine ("adc %s", lbuf);
1602 AddCodeLine ("bcc %s", LocalLabelName (L));
1603 AddCodeLine ("inx");
1604 g_defcodelabel (L);
1605 break;
1606
1607 case CF_INT:
1608 AddCodeLine ("clc");
1609 AddCodeLine ("adc %s", lbuf);
1610 AddCodeLine ("tay");
1611 AddCodeLine ("txa");
1612 AddCodeLine ("adc %s+1", lbuf);
1613 AddCodeLine ("tax");
1614 AddCodeLine ("tya");
1615 break;
1616
1617 case CF_LONG:
1618 /* Do it the old way */
1619 g_push (flags, 0);
1620 g_getstatic (flags, label, offs);
1621 g_add (flags, 0);
1622 break;
1623
1624 default:
1625 typeerror (flags);
1626
1627 }
1628}
1629
1630
1631
1632/*****************************************************************************/
1633/* Special op= functions */
1634/*****************************************************************************/
1635
1636
1637
1638void g_addeqstatic (unsigned flags, uintptr_t label, long offs,
1639 unsigned long val)
1640/* Emit += for a static variable */
1641{
1642 /* Create the correct label name */
1643 const char* lbuf = GetLabelName (flags, label, offs);
1644
1645 /* Check the size and determine operation */
1646 switch (flags & CF_TYPEMASK) {
1647
1648 case CF_CHAR:
1649 if (flags & CF_FORCECHAR) {
1650 AddCodeLine ("ldx #$00");
1651 if (flags & CF_CONST) {
1652 if (val == 1) {
1653 AddCodeLine ("inc %s", lbuf);
1654 AddCodeLine ("lda %s", lbuf);
1655 } else {
1656 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1657 AddCodeLine ("clc");
1658 AddCodeLine ("adc %s", lbuf);
1659 AddCodeLine ("sta %s", lbuf);
1660 }
1661 } else {
1662 AddCodeLine ("clc");
1663 AddCodeLine ("adc %s", lbuf);
1664 AddCodeLine ("sta %s", lbuf);
1665 }
1666 if ((flags & CF_UNSIGNED) == 0) {
1667 unsigned L = GetLocalLabel();
1668 AddCodeLine ("bpl %s", LocalLabelName (L));
1669 AddCodeLine ("dex");
1670 g_defcodelabel (L);
1671 }
1672 break;
1673 }
1674 /* FALLTHROUGH */
1675
1676 case CF_INT:
1677 if (flags & CF_CONST) {
1678 if (val == 1) {
1679 unsigned L = GetLocalLabel ();
1680 AddCodeLine ("inc %s", lbuf);
1681 AddCodeLine ("bne %s", LocalLabelName (L));
1682 AddCodeLine ("inc %s+1", lbuf);
1683 g_defcodelabel (L);
1684 AddCodeLine ("lda %s", lbuf); /* Hmmm... */
1685 AddCodeLine ("ldx %s+1", lbuf);
1686 } else {
1687 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1688 AddCodeLine ("clc");
1689 AddCodeLine ("adc %s", lbuf);
1690 AddCodeLine ("sta %s", lbuf);
1691 if (val < 0x100) {
1692 unsigned L = GetLocalLabel ();
1693 AddCodeLine ("bcc %s", LocalLabelName (L));
1694 AddCodeLine ("inc %s+1", lbuf);
1695 g_defcodelabel (L);
1696 AddCodeLine ("ldx %s+1", lbuf);
1697 } else {
1698 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1699 AddCodeLine ("adc %s+1", lbuf);
1700 AddCodeLine ("sta %s+1", lbuf);
1701 AddCodeLine ("tax");
1702 AddCodeLine ("lda %s", lbuf);
1703 }
1704 }
1705 } else {
1706 AddCodeLine ("clc");
1707 AddCodeLine ("adc %s", lbuf);
1708 AddCodeLine ("sta %s", lbuf);
1709 AddCodeLine ("txa");
1710 AddCodeLine ("adc %s+1", lbuf);
1711 AddCodeLine ("sta %s+1", lbuf);
1712 AddCodeLine ("tax");
1713 AddCodeLine ("lda %s", lbuf);
1714 }
1715 break;
1716
1717 case CF_LONG:
1718 if (flags & CF_CONST) {
1719 if (val < 0x100) {
1720 AddCodeLine ("ldy #<(%s)", lbuf);
1721 AddCodeLine ("sty ptr1");
1722 AddCodeLine ("ldy #>(%s)", lbuf);
1723 if (val == 1) {
1724 AddCodeLine ("jsr laddeq1");
1725 } else {
1726 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1727 AddCodeLine ("jsr laddeqa");
1728 }
1729 } else {
1730 g_getstatic (flags, label, offs);
1731 g_inc (flags, val);
1732 g_putstatic (flags, label, offs);
1733 }
1734 } else {
1735 AddCodeLine ("ldy #<(%s)", lbuf);
1736 AddCodeLine ("sty ptr1");
1737 AddCodeLine ("ldy #>(%s)", lbuf);
1738 AddCodeLine ("jsr laddeq");
1739 }
1740 break;
1741
1742 default:
1743 typeerror (flags);
1744 }
1745}
1746
1747
1748
1749void g_addeqlocal (unsigned flags, int Offs, unsigned long val)
1750/* Emit += for a local variable */
1751{
1752 /* Calculate the true offset, check it, load it into Y */
1753 Offs -= StackPtr;
1754 CheckLocalOffs (Offs);
1755
1756 /* Check the size and determine operation */
1757 switch (flags & CF_TYPEMASK) {
1758
1759 case CF_CHAR:
1760 if (flags & CF_FORCECHAR) {
1761 AddCodeLine ("ldy #$%02X", Offs);
1762 AddCodeLine ("ldx #$00");
1763 if (flags & CF_CONST) {
1764 AddCodeLine ("clc");
1765 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1766 AddCodeLine ("adc (sp),y");
1767 AddCodeLine ("sta (sp),y");
1768 } else {
1769 AddCodeLine ("clc");
1770 AddCodeLine ("adc (sp),y");
1771 AddCodeLine ("sta (sp),y");
1772 }
1773 if ((flags & CF_UNSIGNED) == 0) {
1774 unsigned L = GetLocalLabel();
1775 AddCodeLine ("bpl %s", LocalLabelName (L));
1776 AddCodeLine ("dex");
1777 g_defcodelabel (L);
1778 }
1779 break;
1780 }
1781 /* FALLTHROUGH */
1782
1783 case CF_INT:
1784 AddCodeLine ("ldy #$%02X", Offs);
1785 if (flags & CF_CONST) {
1786 if (IS_Get (&CodeSizeFactor) >= 400) {
1787 AddCodeLine ("clc");
1788 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1789 AddCodeLine ("adc (sp),y");
1790 AddCodeLine ("sta (sp),y");
1791 AddCodeLine ("iny");
1792 AddCodeLine ("lda #$%02X", (int) ((val >> 8) & 0xFF));
1793 AddCodeLine ("adc (sp),y");
1794 AddCodeLine ("sta (sp),y");
1795 AddCodeLine ("tax");
1796 AddCodeLine ("dey");
1797 AddCodeLine ("lda (sp),y");
1798 } else {
1799 g_getimmed (flags, val, 0);
1800 AddCodeLine ("jsr addeqysp");
1801 }
1802 } else {
1803 AddCodeLine ("jsr addeqysp");
1804 }
1805 break;
1806
1807 case CF_LONG:
1808 if (flags & CF_CONST) {
1809 g_getimmed (flags, val, 0);
1810 }
1811 AddCodeLine ("ldy #$%02X", Offs);
1812 AddCodeLine ("jsr laddeqysp");
1813 break;
1814
1815 default:
1816 typeerror (flags);
1817 }
1818}
1819
1820
1821
1822void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
1823/* Emit += for the location with address in ax */
1824{
1825 /* If the offset is too large for a byte register, add the high byte
1826 ** of the offset to the primary. Beware: We need a special correction
1827 ** if the offset in the low byte will overflow in the operation.
1828 */
1829 offs = MakeByteOffs (flags, offs);
1830
1831 /* Check the size and determine operation */
1832 switch (flags & CF_TYPEMASK) {
1833
1834 case CF_CHAR:
1835 AddCodeLine ("sta ptr1");
1836 AddCodeLine ("stx ptr1+1");
1837 AddCodeLine ("ldy #$%02X", offs);
1838 AddCodeLine ("ldx #$00");
1839 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1840 AddCodeLine ("clc");
1841 AddCodeLine ("adc (ptr1),y");
1842 AddCodeLine ("sta (ptr1),y");
1843 break;
1844
1845 case CF_INT:
1846 case CF_LONG:
1847 AddCodeLine ("jsr pushax"); /* Push the address */
1848 push (CF_PTR); /* Correct the internal sp */
1849 g_getind (flags, offs); /* Fetch the value */
1850 g_inc (flags, val); /* Increment value in primary */
1851 g_putind (flags, offs); /* Store the value back */
1852 break;
1853
1854 default:
1855 typeerror (flags);
1856 }
1857}
1858
1859
1860
1861void g_subeqstatic (unsigned flags, uintptr_t label, long offs,
1862 unsigned long val)
1863/* Emit -= for a static variable */
1864{
1865 /* Create the correct label name */
1866 const char* lbuf = GetLabelName (flags, label, offs);
1867
1868 /* Check the size and determine operation */
1869 switch (flags & CF_TYPEMASK) {
1870
1871 case CF_CHAR:
1872 if (flags & CF_FORCECHAR) {
1873 AddCodeLine ("ldx #$00");
1874 if (flags & CF_CONST) {
1875 if (val == 1) {
1876 AddCodeLine ("dec %s", lbuf);
1877 AddCodeLine ("lda %s", lbuf);
1878 } else {
1879 AddCodeLine ("lda %s", lbuf);
1880 AddCodeLine ("sec");
1881 AddCodeLine ("sbc #$%02X", (int)(val & 0xFF));
1882 AddCodeLine ("sta %s", lbuf);
1883 }
1884 } else {
1885 AddCodeLine ("eor #$FF");
1886 AddCodeLine ("sec");
1887 AddCodeLine ("adc %s", lbuf);
1888 AddCodeLine ("sta %s", lbuf);
1889 }
1890 if ((flags & CF_UNSIGNED) == 0) {
1891 unsigned L = GetLocalLabel();
1892 AddCodeLine ("bpl %s", LocalLabelName (L));
1893 AddCodeLine ("dex");
1894 g_defcodelabel (L);
1895 }
1896 break;
1897 }
1898 /* FALLTHROUGH */
1899
1900 case CF_INT:
1901 if (flags & CF_CONST) {
1902 AddCodeLine ("lda %s", lbuf);
1903 AddCodeLine ("sec");
1904 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1905 AddCodeLine ("sta %s", lbuf);
1906 if (val < 0x100) {
1907 unsigned L = GetLocalLabel ();
1908 AddCodeLine ("bcs %s", LocalLabelName (L));
1909 AddCodeLine ("dec %s+1", lbuf);
1910 g_defcodelabel (L);
1911 AddCodeLine ("ldx %s+1", lbuf);
1912 } else {
1913 AddCodeLine ("lda %s+1", lbuf);
1914 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
1915 AddCodeLine ("sta %s+1", lbuf);
1916 AddCodeLine ("tax");
1917 AddCodeLine ("lda %s", lbuf);
1918 }
1919 } else {
1920 AddCodeLine ("eor #$FF");
1921 AddCodeLine ("sec");
1922 AddCodeLine ("adc %s", lbuf);
1923 AddCodeLine ("sta %s", lbuf);
1924 AddCodeLine ("txa");
1925 AddCodeLine ("eor #$FF");
1926 AddCodeLine ("adc %s+1", lbuf);
1927 AddCodeLine ("sta %s+1", lbuf);
1928 AddCodeLine ("tax");
1929 AddCodeLine ("lda %s", lbuf);
1930 }
1931 break;
1932
1933 case CF_LONG:
1934 if (flags & CF_CONST) {
1935 if (val < 0x100) {
1936 AddCodeLine ("ldy #<(%s)", lbuf);
1937 AddCodeLine ("sty ptr1");
1938 AddCodeLine ("ldy #>(%s)", lbuf);
1939 AddCodeLine ("lda #$%02X", (unsigned char)val);
1940 AddCodeLine ("jsr lsubeqa");
1941 } else {
1942 g_getstatic (flags, label, offs);
1943 g_dec (flags, val);
1944 g_putstatic (flags, label, offs);
1945 }
1946 } else {
1947 AddCodeLine ("ldy #<(%s)", lbuf);
1948 AddCodeLine ("sty ptr1");
1949 AddCodeLine ("ldy #>(%s)", lbuf);
1950 AddCodeLine ("jsr lsubeq");
1951 }
1952 break;
1953
1954 default:
1955 typeerror (flags);
1956 }
1957}
1958
1959
1960
1961void g_subeqlocal (unsigned flags, int Offs, unsigned long val)
1962/* Emit -= for a local variable */
1963{
1964 /* Calculate the true offset, check it, load it into Y */
1965 Offs -= StackPtr;
1966 CheckLocalOffs (Offs);
1967
1968 /* Check the size and determine operation */
1969 switch (flags & CF_TYPEMASK) {
1970
1971 case CF_CHAR:
1972 if (flags & CF_FORCECHAR) {
1973 AddCodeLine ("ldy #$%02X", Offs);
1974 AddCodeLine ("ldx #$00");
1975 if (flags & CF_CONST) {
1976 AddCodeLine ("lda (sp),y");
1977 AddCodeLine ("sec");
1978 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1979 } else {
1980 AddCodeLine ("eor #$FF");
1981 AddCodeLine ("sec");
1982 AddCodeLine ("adc (sp),y");
1983 }
1984 AddCodeLine ("sta (sp),y");
1985 if ((flags & CF_UNSIGNED) == 0) {
1986 unsigned L = GetLocalLabel();
1987 AddCodeLine ("bpl %s", LocalLabelName (L));
1988 AddCodeLine ("dex");
1989 g_defcodelabel (L);
1990 }
1991 break;
1992 }
1993 /* FALLTHROUGH */
1994
1995 case CF_INT:
1996 if (flags & CF_CONST) {
1997 g_getimmed (flags, val, 0);
1998 }
1999 AddCodeLine ("ldy #$%02X", Offs);
2000 AddCodeLine ("jsr subeqysp");
2001 break;
2002
2003 case CF_LONG:
2004 if (flags & CF_CONST) {
2005 g_getimmed (flags, val, 0);
2006 }
2007 AddCodeLine ("ldy #$%02X", Offs);
2008 AddCodeLine ("jsr lsubeqysp");
2009 break;
2010
2011 default:
2012 typeerror (flags);
2013 }
2014}
2015
2016
2017
2018void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
2019/* Emit -= for the location with address in ax */
2020{
2021 /* If the offset is too large for a byte register, add the high byte
2022 ** of the offset to the primary. Beware: We need a special correction
2023 ** if the offset in the low byte will overflow in the operation.
2024 */
2025 offs = MakeByteOffs (flags, offs);
2026
2027 /* Check the size and determine operation */
2028 switch (flags & CF_TYPEMASK) {
2029
2030 case CF_CHAR:
2031 AddCodeLine ("sta ptr1");
2032 AddCodeLine ("stx ptr1+1");
2033 AddCodeLine ("ldy #$%02X", offs);
2034 AddCodeLine ("ldx #$00");
2035 AddCodeLine ("lda (ptr1),y");
2036 AddCodeLine ("sec");
2037 AddCodeLine ("sbc #$%02X", (unsigned char)val);
2038 AddCodeLine ("sta (ptr1),y");
2039 break;
2040
2041 case CF_INT:
2042 case CF_LONG:
2043 AddCodeLine ("jsr pushax"); /* Push the address */
2044 push (CF_PTR); /* Correct the internal sp */
2045 g_getind (flags, offs); /* Fetch the value */
2046 g_dec (flags, val); /* Increment value in primary */
2047 g_putind (flags, offs); /* Store the value back */
2048 break;
2049
2050 default:
2051 typeerror (flags);
2052 }
2053}
2054
2055
2056
2057/*****************************************************************************/
2058/* Add a variable address to the value in ax */
2059/*****************************************************************************/
2060
2061
2062
2063void g_addaddr_local (unsigned flags attribute ((unused)), int offs)
2064/* Add the address of a local variable to ax */
2065{
2066 unsigned L = 0;
2067
2068 /* Add the offset */
2069 offs -= StackPtr;
2070 if (offs != 0) {
2071 /* We cannot address more then 256 bytes of locals anyway */
2072 L = GetLocalLabel();
2073 CheckLocalOffs (offs);
2074 AddCodeLine ("clc");
2075 AddCodeLine ("adc #$%02X", offs & 0xFF);
2076 /* Do also skip the CLC insn below */
2077 AddCodeLine ("bcc %s", LocalLabelName (L));
2078 AddCodeLine ("inx");
2079 }
2080
2081 /* Add the current stackpointer value */
2082 AddCodeLine ("clc");
2083 if (L != 0) {
2084 /* Label was used above */
2085 g_defcodelabel (L);
2086 }
2087 AddCodeLine ("adc sp");
2088 AddCodeLine ("tay");
2089 AddCodeLine ("txa");
2090 AddCodeLine ("adc sp+1");
2091 AddCodeLine ("tax");
2092 AddCodeLine ("tya");
2093}
2094
2095
2096
2097void g_addaddr_static (unsigned flags, uintptr_t label, long offs)
2098/* Add the address of a static variable to ax */
2099{
2100 /* Create the correct label name */
2101 const char* lbuf = GetLabelName (flags, label, offs);
2102
2103 /* Add the address to the current ax value */
2104 AddCodeLine ("clc");
2105 AddCodeLine ("adc #<(%s)", lbuf);
2106 AddCodeLine ("tay");
2107 AddCodeLine ("txa");
2108 AddCodeLine ("adc #>(%s)", lbuf);
2109 AddCodeLine ("tax");
2110 AddCodeLine ("tya");
2111}
2112
2113
2114
2115/*****************************************************************************/
2116/* */
2117/*****************************************************************************/
2118
2119
2120
2121void g_save (unsigned flags)
2122/* Copy primary register to hold register. */
2123{
2124 /* Check the size and determine operation */
2125 switch (flags & CF_TYPEMASK) {
2126
2127 case CF_CHAR:
2128 if (flags & CF_FORCECHAR) {
2129 AddCodeLine ("pha");
2130 break;
2131 }
2132 /* FALLTHROUGH */
2133
2134 case CF_INT:
2135 AddCodeLine ("sta regsave");
2136 AddCodeLine ("stx regsave+1");
2137 break;
2138
2139 case CF_LONG:
2140 AddCodeLine ("jsr saveeax");
2141 break;
2142
2143 default:
2144 typeerror (flags);
2145 }
2146}
2147
2148
2149
2150void g_restore (unsigned flags)
2151/* Copy hold register to primary. */
2152{
2153 /* Check the size and determine operation */
2154 switch (flags & CF_TYPEMASK) {
2155
2156 case CF_CHAR:
2157 if (flags & CF_FORCECHAR) {
2158 AddCodeLine ("pla");
2159 break;
2160 }
2161 /* FALLTHROUGH */
2162
2163 case CF_INT:
2164 AddCodeLine ("lda regsave");
2165 AddCodeLine ("ldx regsave+1");
2166 break;
2167
2168 case CF_LONG:
2169 AddCodeLine ("jsr resteax");
2170 break;
2171
2172 default:
2173 typeerror (flags);
2174 }
2175}
2176
2177
2178
2179void g_cmp (unsigned flags, unsigned long val)
2180/* Immidiate compare. The primary register will not be changed, Z flag
2181** will be set.
2182*/
2183{
2184 unsigned L;
2185
2186 /* Check the size and determine operation */
2187 switch (flags & CF_TYPEMASK) {
2188
2189 case CF_CHAR:
2190 if (flags & CF_FORCECHAR) {
2191 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2192 break;
2193 }
2194 /* FALLTHROUGH */
2195
2196 case CF_INT:
2197 L = GetLocalLabel();
2198 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2199 AddCodeLine ("bne %s", LocalLabelName (L));
2200 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
2201 g_defcodelabel (L);
2202 break;
2203
2204 case CF_LONG:
2205 Internal ("g_cmp: Long compares not implemented");
2206 break;
2207
2208 default:
2209 typeerror (flags);
2210 }
2211}
2212
2213
2214
2215static void oper (unsigned Flags, unsigned long Val, const char* const* Subs)
2216/* Encode a binary operation. subs is a pointer to four strings:
2217** 0 --> Operate on ints
2218** 1 --> Operate on unsigneds
2219** 2 --> Operate on longs
2220** 3 --> Operate on unsigned longs
2221*/
2222{
2223 /* Determine the offset into the array */
2224 if (Flags & CF_UNSIGNED) {
2225 ++Subs;
2226 }
2227 if ((Flags & CF_TYPEMASK) == CF_LONG) {
2228 Subs += 2;
2229 }
2230
2231 /* Load the value if it is not already in the primary */
2232 if (Flags & CF_CONST) {
2233 /* Load value */
2234 g_getimmed (Flags, Val, 0);
2235 }
2236
2237 /* Output the operation */
2238 AddCodeLine ("jsr %s", *Subs);
2239
2240 /* The operation will pop it's argument */
2241 pop (Flags);
2242}
2243
2244
2245
2246void g_test (unsigned flags)
2247/* Test the value in the primary and set the condition codes */
2248{
2249 switch (flags & CF_TYPEMASK) {
2250
2251 case CF_CHAR:
2252 if (flags & CF_FORCECHAR) {
2253 AddCodeLine ("tax");
2254 break;
2255 }
2256 /* FALLTHROUGH */
2257
2258 case CF_INT:
2259 AddCodeLine ("stx tmp1");
2260 AddCodeLine ("ora tmp1");
2261 break;
2262
2263 case CF_LONG:
2264 if (flags & CF_UNSIGNED) {
2265 AddCodeLine ("jsr utsteax");
2266 } else {
2267 AddCodeLine ("jsr tsteax");
2268 }
2269 break;
2270
2271 default:
2272 typeerror (flags);
2273
2274 }
2275}
2276
2277
2278
2279void g_push (unsigned flags, unsigned long val)
2280/* Push the primary register or a constant value onto the stack */
2281{
2282 if (flags & CF_CONST && (flags & CF_TYPEMASK) != CF_LONG) {
2283
2284 /* We have a constant 8 or 16 bit value */
2285 if ((flags & CF_TYPEMASK) == CF_CHAR && (flags & CF_FORCECHAR)) {
2286
2287 /* Handle as 8 bit value */
2288 AddCodeLine ("lda #$%02X", (unsigned char) val);
2289 AddCodeLine ("jsr pusha");
2290
2291 } else {
2292
2293 /* Handle as 16 bit value */
2294 g_getimmed (flags, val, 0);
2295 AddCodeLine ("jsr pushax");
2296 }
2297
2298 } else {
2299
2300 /* Value is not 16 bit or not constant */
2301 if (flags & CF_CONST) {
2302 /* Constant 32 bit value, load into eax */
2303 g_getimmed (flags, val, 0);
2304 }
2305
2306 /* Push the primary register */
2307 switch (flags & CF_TYPEMASK) {
2308
2309 case CF_CHAR:
2310 if (flags & CF_FORCECHAR) {
2311 /* Handle as char */
2312 AddCodeLine ("jsr pusha");
2313 break;
2314 }
2315 /* FALL THROUGH */
2316 case CF_INT:
2317 AddCodeLine ("jsr pushax");
2318 break;
2319
2320 case CF_LONG:
2321 AddCodeLine ("jsr pusheax");
2322 break;
2323
2324 default:
2325 typeerror (flags);
2326
2327 }
2328
2329 }
2330
2331 /* Adjust the stack offset */
2332 push (flags);
2333}
2334
2335
2336
2337void g_swap (unsigned flags)
2338/* Swap the primary register and the top of the stack. flags give the type
2339** of *both* values (must have same size).
2340*/
2341{
2342 switch (flags & CF_TYPEMASK) {
2343
2344 case CF_CHAR:
2345 case CF_INT:
2346 AddCodeLine ("jsr swapstk");
2347 break;
2348
2349 case CF_LONG:
2350 AddCodeLine ("jsr swapestk");
2351 break;
2352
2353 default:
2354 typeerror (flags);
2355
2356 }
2357}
2358
2359
2360
2361void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
2362/* Call the specified subroutine name */
2363{
2364 if ((Flags & CF_FIXARGC) == 0) {
2365 /* Pass the argument count */
2366 AddCodeLine ("ldy #$%02X", ArgSize);
2367 }
2368 AddCodeLine ("jsr _%s", Label);
2369 StackPtr += ArgSize; /* callee pops args */
2370}
2371
2372
2373
2374void g_callind (unsigned Flags, unsigned ArgSize, int Offs)
2375/* Call subroutine indirect */
2376{
2377 if ((Flags & CF_LOCAL) == 0) {
2378 /* Address is in a/x */
2379 if ((Flags & CF_FIXARGC) == 0) {
2380 /* Pass arg count */
2381 AddCodeLine ("ldy #$%02X", ArgSize);
2382 }
2383 AddCodeLine ("jsr callax");
2384 } else {
2385 /* The address is on stack, offset is on Val */
2386 Offs -= StackPtr;
2387 CheckLocalOffs (Offs);
2388 AddCodeLine ("pha");
2389 AddCodeLine ("ldy #$%02X", Offs);
2390 AddCodeLine ("lda (sp),y");
2391 AddCodeLine ("sta jmpvec+1");
2392 AddCodeLine ("iny");
2393 AddCodeLine ("lda (sp),y");
2394 AddCodeLine ("sta jmpvec+2");
2395 AddCodeLine ("pla");
2396 AddCodeLine ("jsr jmpvec");
2397 }
2398
2399 /* Callee pops args */
2400 StackPtr += ArgSize;
2401}
2402
2403
2404
2405void g_jump (unsigned Label)
2406/* Jump to specified internal label number */
2407{
2408 AddCodeLine ("jmp %s", LocalLabelName (Label));
2409}
2410
2411
2412
2413void g_truejump (unsigned flags attribute ((unused)), unsigned label)
2414/* Jump to label if zero flag clear */
2415{
2416 AddCodeLine ("jne %s", LocalLabelName (label));
2417}
2418
2419
2420
2421void g_falsejump (unsigned flags attribute ((unused)), unsigned label)
2422/* Jump to label if zero flag set */
2423{
2424 AddCodeLine ("jeq %s", LocalLabelName (label));
2425}
2426
2427
2428void g_lateadjustSP (unsigned label)
2429/* Adjust stack based on non-immediate data */
2430{
2431 AddCodeLine ("pha");
2432 AddCodeLine ("lda %s", LocalLabelName (label));
2433 AddCodeLine ("clc");
2434 AddCodeLine ("adc sp");
2435 AddCodeLine ("sta sp");
2436 AddCodeLine ("lda %s+1", LocalLabelName (label));
2437 AddCodeLine ("adc sp+1");
2438 AddCodeLine ("sta sp+1");
2439 AddCodeLine ("pla");
2440}
2441
2442void g_drop (unsigned Space)
2443/* Drop space allocated on the stack */
2444{
2445 if (Space > 255) {
2446 /* Inline the code since calling addysp repeatedly is quite some
2447 ** overhead.
2448 */
2449 AddCodeLine ("pha");
2450 AddCodeLine ("lda #$%02X", (unsigned char) Space);
2451 AddCodeLine ("clc");
2452 AddCodeLine ("adc sp");
2453 AddCodeLine ("sta sp");
2454 AddCodeLine ("lda #$%02X", (unsigned char) (Space >> 8));
2455 AddCodeLine ("adc sp+1");
2456 AddCodeLine ("sta sp+1");
2457 AddCodeLine ("pla");
2458 } else if (Space > 8) {
2459 AddCodeLine ("ldy #$%02X", Space);
2460 AddCodeLine ("jsr addysp");
2461 } else if (Space != 0) {
2462 AddCodeLine ("jsr incsp%u", Space);
2463 }
2464}
2465
2466
2467
2468void g_space (int Space)
2469/* Create or drop space on the stack */
2470{
2471 if (Space < 0) {
2472 /* This is actually a drop operation */
2473 g_drop (-Space);
2474 } else if (Space > 255) {
2475 /* Inline the code since calling subysp repeatedly is quite some
2476 ** overhead.
2477 */
2478 AddCodeLine ("pha");
2479 AddCodeLine ("lda sp");
2480 AddCodeLine ("sec");
2481 AddCodeLine ("sbc #$%02X", (unsigned char) Space);
2482 AddCodeLine ("sta sp");
2483 AddCodeLine ("lda sp+1");
2484 AddCodeLine ("sbc #$%02X", (unsigned char) (Space >> 8));
2485 AddCodeLine ("sta sp+1");
2486 AddCodeLine ("pla");
2487 } else if (Space > 8) {
2488 AddCodeLine ("ldy #$%02X", Space);
2489 AddCodeLine ("jsr subysp");
2490 } else if (Space != 0) {
2491 AddCodeLine ("jsr decsp%u", Space);
2492 }
2493}
2494
2495
2496
2497void g_cstackcheck (void)
2498/* Check for a C stack overflow */
2499{
2500 AddCodeLine ("jsr cstkchk");
2501}
2502
2503
2504
2505void g_stackcheck (void)
2506/* Check for a stack overflow */
2507{
2508 AddCodeLine ("jsr stkchk");
2509}
2510
2511
2512
2513void g_add (unsigned flags, unsigned long val)
2514/* Primary = TOS + Primary */
2515{
2516 static const char* const ops[4] = {
2517 "tosaddax", "tosaddax", "tosaddeax", "tosaddeax"
2518 };
2519
2520 if (flags & CF_CONST) {
2521 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2522 g_push (flags & ~CF_CONST, 0);
2523 }
2524 oper (flags, val, ops);
2525}
2526
2527
2528
2529void g_sub (unsigned flags, unsigned long val)
2530/* Primary = TOS - Primary */
2531{
2532 static const char* const ops[4] = {
2533 "tossubax", "tossubax", "tossubeax", "tossubeax"
2534 };
2535
2536 if (flags & CF_CONST) {
2537 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2538 g_push (flags & ~CF_CONST, 0);
2539 }
2540 oper (flags, val, ops);
2541}
2542
2543
2544
2545void g_rsub (unsigned flags, unsigned long val)
2546/* Primary = Primary - TOS */
2547{
2548 static const char* const ops[4] = {
2549 "tosrsubax", "tosrsubax", "tosrsubeax", "tosrsubeax"
2550 };
2551 oper (flags, val, ops);
2552}
2553
2554
2555
2556void g_mul (unsigned flags, unsigned long val)
2557/* Primary = TOS * Primary */
2558{
2559 static const char* const ops[4] = {
2560 "tosmulax", "tosumulax", "tosmuleax", "tosumuleax"
2561 };
2562
2563 int p2;
2564
2565 /* Do strength reduction if the value is constant and a power of two */
2566 if (flags & CF_CONST && (p2 = PowerOf2 (val)) >= 0) {
2567 /* Generate a shift instead */
2568 g_asl (flags, p2);
2569 return;
2570 }
2571
2572 /* If the right hand side is const, the lhs is not on stack but still
2573 ** in the primary register.
2574 */
2575 if (flags & CF_CONST) {
2576
2577 switch (flags & CF_TYPEMASK) {
2578
2579 case CF_CHAR:
2580 if (flags & CF_FORCECHAR) {
2581 /* Handle some special cases */
2582 switch (val) {
2583
2584 case 3:
2585 AddCodeLine ("sta tmp1");
2586 AddCodeLine ("asl a");
2587 AddCodeLine ("clc");
2588 AddCodeLine ("adc tmp1");
2589 return;
2590
2591 case 5:
2592 AddCodeLine ("sta tmp1");
2593 AddCodeLine ("asl a");
2594 AddCodeLine ("asl a");
2595 AddCodeLine ("clc");
2596 AddCodeLine ("adc tmp1");
2597 return;
2598
2599 case 6:
2600 AddCodeLine ("sta tmp1");
2601 AddCodeLine ("asl a");
2602 AddCodeLine ("clc");
2603 AddCodeLine ("adc tmp1");
2604 AddCodeLine ("asl a");
2605 return;
2606
2607 case 10:
2608 AddCodeLine ("sta tmp1");
2609 AddCodeLine ("asl a");
2610 AddCodeLine ("asl a");
2611 AddCodeLine ("clc");
2612 AddCodeLine ("adc tmp1");
2613 AddCodeLine ("asl a");
2614 return;
2615 }
2616 }
2617 /* FALLTHROUGH */
2618
2619 case CF_INT:
2620 switch (val) {
2621 case 3:
2622 AddCodeLine ("jsr mulax3");
2623 return;
2624 case 5:
2625 AddCodeLine ("jsr mulax5");
2626 return;
2627 case 6:
2628 AddCodeLine ("jsr mulax6");
2629 return;
2630 case 7:
2631 AddCodeLine ("jsr mulax7");
2632 return;
2633 case 9:
2634 AddCodeLine ("jsr mulax9");
2635 return;
2636 case 10:
2637 AddCodeLine ("jsr mulax10");
2638 return;
2639 }
2640 break;
2641
2642 case CF_LONG:
2643 break;
2644
2645 default:
2646 typeerror (flags);
2647 }
2648
2649 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2650 ** into the normal, non-optimized stuff.
2651 */
2652 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2653 g_push (flags & ~CF_CONST, 0);
2654
2655 }
2656
2657 /* Use long way over the stack */
2658 oper (flags, val, ops);
2659}
2660
2661
2662
2663void g_div (unsigned flags, unsigned long val)
2664/* Primary = TOS / Primary */
2665{
2666 static const char* const ops[4] = {
2667 "tosdivax", "tosudivax", "tosdiveax", "tosudiveax"
2668 };
2669
2670 /* Do strength reduction if the value is constant and a power of two */
2671 int p2;
2672 if ((flags & CF_CONST) && (p2 = PowerOf2 (val)) >= 0) {
2673 /* Generate a shift instead */
2674 g_asr (flags, p2);
2675 } else {
2676 /* Generate a division */
2677 if (flags & CF_CONST) {
2678 /* lhs is not on stack */
2679 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2680 g_push (flags & ~CF_CONST, 0);
2681 }
2682 oper (flags, val, ops);
2683 }
2684}
2685
2686
2687
2688void g_mod (unsigned flags, unsigned long val)
2689/* Primary = TOS % Primary */
2690{
2691 static const char* const ops[4] = {
2692 "tosmodax", "tosumodax", "tosmodeax", "tosumodeax"
2693 };
2694 int p2;
2695
2696 /* Check if we can do some cost reduction */
2697 if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = PowerOf2 (val)) >= 0) {
2698 /* We can do that with an AND operation */
2699 g_and (flags, val - 1);
2700 } else {
2701 /* Do it the hard way... */
2702 if (flags & CF_CONST) {
2703 /* lhs is not on stack */
2704 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2705 g_push (flags & ~CF_CONST, 0);
2706 }
2707 oper (flags, val, ops);
2708 }
2709}
2710
2711
2712
2713void g_or (unsigned flags, unsigned long val)
2714/* Primary = TOS | Primary */
2715{
2716 static const char* const ops[4] = {
2717 "tosorax", "tosorax", "tosoreax", "tosoreax"
2718 };
2719
2720 /* If the right hand side is const, the lhs is not on stack but still
2721 ** in the primary register.
2722 */
2723 if (flags & CF_CONST) {
2724
2725 switch (flags & CF_TYPEMASK) {
2726
2727 case CF_CHAR:
2728 if (flags & CF_FORCECHAR) {
2729 if ((val & 0xFF) != 0) {
2730 AddCodeLine ("ora #$%02X", (unsigned char)val);
2731 }
2732 return;
2733 }
2734 /* FALLTHROUGH */
2735
2736 case CF_INT:
2737 if (val <= 0xFF) {
2738 if ((val & 0xFF) != 0) {
2739 AddCodeLine ("ora #$%02X", (unsigned char)val);
2740 }
2741 } else if ((val & 0xFF00) == 0xFF00) {
2742 if ((val & 0xFF) != 0) {
2743 AddCodeLine ("ora #$%02X", (unsigned char)val);
2744 }
2745 AddCodeLine ("ldx #$FF");
2746 } else if (val != 0) {
2747 AddCodeLine ("ora #$%02X", (unsigned char)val);
2748 AddCodeLine ("pha");
2749 AddCodeLine ("txa");
2750 AddCodeLine ("ora #$%02X", (unsigned char)(val >> 8));
2751 AddCodeLine ("tax");
2752 AddCodeLine ("pla");
2753 }
2754 return;
2755
2756 case CF_LONG:
2757 if (val <= 0xFF) {
2758 if ((val & 0xFF) != 0) {
2759 AddCodeLine ("ora #$%02X", (unsigned char)val);
2760 }
2761 return;
2762 }
2763 break;
2764
2765 default:
2766 typeerror (flags);
2767 }
2768
2769 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2770 ** into the normal, non-optimized stuff. Note: The standard stuff will
2771 ** always work with ints.
2772 */
2773 flags &= ~CF_FORCECHAR;
2774 g_push (flags & ~CF_CONST, 0);
2775 }
2776
2777 /* Use long way over the stack */
2778 oper (flags, val, ops);
2779}
2780
2781
2782
2783void g_xor (unsigned flags, unsigned long val)
2784/* Primary = TOS ^ Primary */
2785{
2786 static const char* const ops[4] = {
2787 "tosxorax", "tosxorax", "tosxoreax", "tosxoreax"
2788 };
2789
2790
2791 /* If the right hand side is const, the lhs is not on stack but still
2792 ** in the primary register.
2793 */
2794 if (flags & CF_CONST) {
2795
2796 switch (flags & CF_TYPEMASK) {
2797
2798 case CF_CHAR:
2799 if (flags & CF_FORCECHAR) {
2800 if ((val & 0xFF) != 0) {
2801 AddCodeLine ("eor #$%02X", (unsigned char)val);
2802 }
2803 return;
2804 }
2805 /* FALLTHROUGH */
2806
2807 case CF_INT:
2808 if (val <= 0xFF) {
2809 if (val != 0) {
2810 AddCodeLine ("eor #$%02X", (unsigned char)val);
2811 }
2812 } else if (val != 0) {
2813 if ((val & 0xFF) != 0) {
2814 AddCodeLine ("eor #$%02X", (unsigned char)val);
2815 }
2816 AddCodeLine ("pha");
2817 AddCodeLine ("txa");
2818 AddCodeLine ("eor #$%02X", (unsigned char)(val >> 8));
2819 AddCodeLine ("tax");
2820 AddCodeLine ("pla");
2821 }
2822 return;
2823
2824 case CF_LONG:
2825 if (val <= 0xFF) {
2826 if (val != 0) {
2827 AddCodeLine ("eor #$%02X", (unsigned char)val);
2828 }
2829 return;
2830 }
2831 break;
2832
2833 default:
2834 typeerror (flags);
2835 }
2836
2837 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2838 ** into the normal, non-optimized stuff. Note: The standard stuff will
2839 ** always work with ints.
2840 */
2841 flags &= ~CF_FORCECHAR;
2842 g_push (flags & ~CF_CONST, 0);
2843 }
2844
2845 /* Use long way over the stack */
2846 oper (flags, val, ops);
2847}
2848
2849
2850
2851void g_and (unsigned Flags, unsigned long Val)
2852/* Primary = TOS & Primary */
2853{
2854 static const char* const ops[4] = {
2855 "tosandax", "tosandax", "tosandeax", "tosandeax"
2856 };
2857
2858 /* If the right hand side is const, the lhs is not on stack but still
2859 ** in the primary register.
2860 */
2861 if (Flags & CF_CONST) {
2862
2863 switch (Flags & CF_TYPEMASK) {
2864
2865 case CF_CHAR:
2866 if (Flags & CF_FORCECHAR) {
2867 if ((Val & 0xFF) == 0x00) {
2868 AddCodeLine ("lda #$00");
2869 } else if ((Val & 0xFF) != 0xFF) {
2870 AddCodeLine ("and #$%02X", (unsigned char)Val);
2871 }
2872 return;
2873 }
2874 /* FALLTHROUGH */
2875 case CF_INT:
2876 if ((Val & 0xFFFF) != 0xFFFF) {
2877 if (Val <= 0xFF) {
2878 AddCodeLine ("ldx #$00");
2879 if (Val == 0) {
2880 AddCodeLine ("lda #$00");
2881 } else if (Val != 0xFF) {
2882 AddCodeLine ("and #$%02X", (unsigned char)Val);
2883 }
2884 } else if ((Val & 0xFFFF) == 0xFF00) {
2885 AddCodeLine ("lda #$00");
2886 } else if ((Val & 0xFF00) == 0xFF00) {
2887 AddCodeLine ("and #$%02X", (unsigned char)Val);
2888 } else if ((Val & 0x00FF) == 0x0000) {
2889 AddCodeLine ("txa");
2890 AddCodeLine ("and #$%02X", (unsigned char)(Val >> 8));
2891 AddCodeLine ("tax");
2892 AddCodeLine ("lda #$00");
2893 } else {
2894 AddCodeLine ("tay");
2895 AddCodeLine ("txa");
2896 AddCodeLine ("and #$%02X", (unsigned char)(Val >> 8));
2897 AddCodeLine ("tax");
2898 AddCodeLine ("tya");
2899 if ((Val & 0x00FF) == 0x0000) {
2900 AddCodeLine ("lda #$00");
2901 } else if ((Val & 0x00FF) != 0x00FF) {
2902 AddCodeLine ("and #$%02X", (unsigned char)Val);
2903 }
2904 }
2905 }
2906 return;
2907
2908 case CF_LONG:
2909 if (Val <= 0xFF) {
2910 AddCodeLine ("ldx #$00");
2911 AddCodeLine ("stx sreg+1");
2912 AddCodeLine ("stx sreg");
2913 if ((Val & 0xFF) != 0xFF) {
2914 AddCodeLine ("and #$%02X", (unsigned char)Val);
2915 }
2916 return;
2917 } else if (Val == 0xFF00) {
2918 AddCodeLine ("lda #$00");
2919 AddCodeLine ("sta sreg+1");
2920 AddCodeLine ("sta sreg");
2921 return;
2922 }
2923 break;
2924
2925 default:
2926 typeerror (Flags);
2927 }
2928
2929 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2930 ** into the normal, non-optimized stuff. Note: The standard stuff will
2931 ** always work with ints.
2932 */
2933 Flags &= ~CF_FORCECHAR;
2934 g_push (Flags & ~CF_CONST, 0);
2935 }
2936
2937 /* Use long way over the stack */
2938 oper (Flags, Val, ops);
2939}
2940
2941
2942
2943void g_asr (unsigned flags, unsigned long val)
2944/* Primary = TOS >> Primary */
2945{
2946 static const char* const ops[4] = {
2947 "tosasrax", "tosshrax", "tosasreax", "tosshreax"
2948 };
2949
2950 /* If the right hand side is const, the lhs is not on stack but still
2951 ** in the primary register.
2952 */
2953 if (flags & CF_CONST) {
2954
2955 switch (flags & CF_TYPEMASK) {
2956
2957 case CF_CHAR:
2958 case CF_INT:
2959 val &= 0x0F;
2960 if (val >= 8) {
2961 if (flags & CF_UNSIGNED) {
2962 AddCodeLine ("txa");
2963 AddCodeLine ("ldx #$00");
2964 } else {
2965 unsigned L = GetLocalLabel();
2966 AddCodeLine ("cpx #$80"); /* Sign bit into carry */
2967 AddCodeLine ("txa");
2968 AddCodeLine ("ldx #$00");
2969 AddCodeLine ("bcc %s", LocalLabelName (L));
2970 AddCodeLine ("dex"); /* Make $FF */
2971 g_defcodelabel (L);
2972 }
2973 val -= 8;
2974 }
2975 if (val >= 4) {
2976 if (flags & CF_UNSIGNED) {
2977 AddCodeLine ("jsr shrax4");
2978 } else {
2979 AddCodeLine ("jsr asrax4");
2980 }
2981 val -= 4;
2982 }
2983 if (val > 0) {
2984 if (flags & CF_UNSIGNED) {
2985 AddCodeLine ("jsr shrax%ld", val);
2986 } else {
2987 AddCodeLine ("jsr asrax%ld", val);
2988 }
2989 }
2990 return;
2991
2992 case CF_LONG:
2993 val &= 0x1F;
2994 if (val >= 24) {
2995 AddCodeLine ("ldx #$00");
2996 AddCodeLine ("lda sreg+1");
2997 if ((flags & CF_UNSIGNED) == 0) {
2998 unsigned L = GetLocalLabel();
2999 AddCodeLine ("bpl %s", LocalLabelName (L));
3000 AddCodeLine ("dex");
3001 g_defcodelabel (L);
3002 }
3003 AddCodeLine ("stx sreg");
3004 AddCodeLine ("stx sreg+1");
3005 val -= 24;
3006 }
3007 if (val >= 16) {
3008 AddCodeLine ("ldy #$00");
3009 AddCodeLine ("ldx sreg+1");
3010 if ((flags & CF_UNSIGNED) == 0) {
3011 unsigned L = GetLocalLabel();
3012 AddCodeLine ("bpl %s", LocalLabelName (L));
3013 AddCodeLine ("dey");
3014 g_defcodelabel (L);
3015 }
3016 AddCodeLine ("lda sreg");
3017 AddCodeLine ("sty sreg+1");
3018 AddCodeLine ("sty sreg");
3019 val -= 16;
3020 }
3021 if (val >= 8) {
3022 AddCodeLine ("txa");
3023 AddCodeLine ("ldx sreg");
3024 AddCodeLine ("ldy sreg+1");
3025 AddCodeLine ("sty sreg");
3026 if ((flags & CF_UNSIGNED) == 0) {
3027 unsigned L = GetLocalLabel();
3028 AddCodeLine ("cpy #$80");
3029 AddCodeLine ("ldy #$00");
3030 AddCodeLine ("bcc %s", LocalLabelName (L));
3031 AddCodeLine ("dey");
3032 g_defcodelabel (L);
3033 } else {
3034 AddCodeLine ("ldy #$00");
3035 }
3036 AddCodeLine ("sty sreg+1");
3037 val -= 8;
3038 }
3039 if (val >= 4) {
3040 if (flags & CF_UNSIGNED) {
3041 AddCodeLine ("jsr shreax4");
3042 } else {
3043 AddCodeLine ("jsr asreax4");
3044 }
3045 val -= 4;
3046 }
3047 if (val > 0) {
3048 if (flags & CF_UNSIGNED) {
3049 AddCodeLine ("jsr shreax%ld", val);
3050 } else {
3051 AddCodeLine ("jsr asreax%ld", val);
3052 }
3053 }
3054 return;
3055
3056 default:
3057 typeerror (flags);
3058 }
3059
3060 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3061 ** into the normal, non-optimized stuff. Note: The standard stuff will
3062 ** always work with ints.
3063 */
3064 flags &= ~CF_FORCECHAR;
3065 g_push (flags & ~CF_CONST, 0);
3066 }
3067
3068 /* Use long way over the stack */
3069 oper (flags, val, ops);
3070}
3071
3072
3073
3074void g_asl (unsigned flags, unsigned long val)
3075/* Primary = TOS << Primary */
3076{
3077 static const char* const ops[4] = {
3078 "tosaslax", "tosshlax", "tosasleax", "tosshleax"
3079 };
3080
3081
3082 /* If the right hand side is const, the lhs is not on stack but still
3083 ** in the primary register.
3084 */
3085 if (flags & CF_CONST) {
3086
3087 switch (flags & CF_TYPEMASK) {
3088
3089 case CF_CHAR:
3090 case CF_INT:
3091 val &= 0x0F;
3092 if (val >= 8) {
3093 AddCodeLine ("tax");
3094 AddCodeLine ("lda #$00");
3095 val -= 8;
3096 }
3097 if (val >= 4) {
3098 if (flags & CF_UNSIGNED) {
3099 AddCodeLine ("jsr shlax4");
3100 } else {
3101 AddCodeLine ("jsr aslax4");
3102 }
3103 val -= 4;
3104 }
3105 if (val > 0) {
3106 if (flags & CF_UNSIGNED) {
3107 AddCodeLine ("jsr shlax%ld", val);
3108 } else {
3109 AddCodeLine ("jsr aslax%ld", val);
3110 }
3111 }
3112 return;
3113
3114 case CF_LONG:
3115 val &= 0x1F;
3116 if (val >= 24) {
3117 AddCodeLine ("sta sreg+1");
3118 AddCodeLine ("lda #$00");
3119 AddCodeLine ("tax");
3120 AddCodeLine ("sta sreg");
3121 val -= 24;
3122 }
3123 if (val >= 16) {
3124 AddCodeLine ("stx sreg+1");
3125 AddCodeLine ("sta sreg");
3126 AddCodeLine ("lda #$00");
3127 AddCodeLine ("tax");
3128 val -= 16;
3129 }
3130 if (val >= 8) {
3131 AddCodeLine ("ldy sreg");
3132 AddCodeLine ("sty sreg+1");
3133 AddCodeLine ("stx sreg");
3134 AddCodeLine ("tax");
3135 AddCodeLine ("lda #$00");
3136 val -= 8;
3137 }
3138 if (val > 4) {
3139 if (flags & CF_UNSIGNED) {
3140 AddCodeLine ("jsr shleax4");
3141 } else {
3142 AddCodeLine ("jsr asleax4");
3143 }
3144 val -= 4;
3145 }
3146 if (val > 0) {
3147 if (flags & CF_UNSIGNED) {
3148 AddCodeLine ("jsr shleax%ld", val);
3149 } else {
3150 AddCodeLine ("jsr asleax%ld", val);
3151 }
3152 }
3153 return;
3154
3155 default:
3156 typeerror (flags);
3157 }
3158
3159 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3160 ** into the normal, non-optimized stuff. Note: The standard stuff will
3161 ** always work with ints.
3162 */
3163 flags &= ~CF_FORCECHAR;
3164 g_push (flags & ~CF_CONST, 0);
3165 }
3166
3167 /* Use long way over the stack */
3168 oper (flags, val, ops);
3169}
3170
3171
3172
3173void g_neg (unsigned Flags)
3174/* Primary = -Primary */
3175{
3176 switch (Flags & CF_TYPEMASK) {
3177
3178 case CF_CHAR:
3179 if (Flags & CF_FORCECHAR) {
3180 AddCodeLine ("eor #$FF");
3181 AddCodeLine ("clc");
3182 AddCodeLine ("adc #$01");
3183 return;
3184 }
3185 /* FALLTHROUGH */
3186
3187 case CF_INT:
3188 AddCodeLine ("jsr negax");
3189 break;
3190
3191 case CF_LONG:
3192 AddCodeLine ("jsr negeax");
3193 break;
3194
3195 default:
3196 typeerror (Flags);
3197 }
3198}
3199
3200
3201
3202void g_bneg (unsigned flags)
3203/* Primary = !Primary */
3204{
3205 switch (flags & CF_TYPEMASK) {
3206
3207 case CF_CHAR:
3208 AddCodeLine ("jsr bnega");
3209 break;
3210
3211 case CF_INT:
3212 AddCodeLine ("jsr bnegax");
3213 break;
3214
3215 case CF_LONG:
3216 AddCodeLine ("jsr bnegeax");
3217 break;
3218
3219 default:
3220 typeerror (flags);
3221 }
3222}
3223
3224
3225
3226void g_com (unsigned Flags)
3227/* Primary = ~Primary */
3228{
3229 switch (Flags & CF_TYPEMASK) {
3230
3231 case CF_CHAR:
3232 if (Flags & CF_FORCECHAR) {
3233 AddCodeLine ("eor #$FF");
3234 return;
3235 }
3236 /* FALLTHROUGH */
3237
3238 case CF_INT:
3239 AddCodeLine ("jsr complax");
3240 break;
3241
3242 case CF_LONG:
3243 AddCodeLine ("jsr compleax");
3244 break;
3245
3246 default:
3247 typeerror (Flags);
3248 }
3249}
3250
3251
3252
3253void g_inc (unsigned flags, unsigned long val)
3254/* Increment the primary register by a given number */
3255{
3256 /* Don't inc by zero */
3257 if (val == 0) {
3258 return;
3259 }
3260
3261 /* Generate code for the supported types */
3262 flags &= ~CF_CONST;
3263 switch (flags & CF_TYPEMASK) {
3264
3265 case CF_CHAR:
3266 if (flags & CF_FORCECHAR) {
3267 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val <= 2) {
3268 while (val--) {
3269 AddCodeLine ("ina");
3270 }
3271 } else {
3272 AddCodeLine ("clc");
3273 AddCodeLine ("adc #$%02X", (unsigned char)val);
3274 }
3275 break;
3276 }
3277 /* FALLTHROUGH */
3278
3279 case CF_INT:
3280 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val == 1) {
3281 unsigned L = GetLocalLabel();
3282 AddCodeLine ("ina");
3283 AddCodeLine ("bne %s", LocalLabelName (L));
3284 AddCodeLine ("inx");
3285 g_defcodelabel (L);
3286 } else if (IS_Get (&CodeSizeFactor) < 200) {
3287 /* Use jsr calls */
3288 if (val <= 8) {
3289 AddCodeLine ("jsr incax%lu", val);
3290 } else if (val <= 255) {
3291 AddCodeLine ("ldy #$%02X", (unsigned char) val);
3292 AddCodeLine ("jsr incaxy");
3293 } else {
3294 g_add (flags | CF_CONST, val);
3295 }
3296 } else {
3297 /* Inline the code */
3298 if (val <= 0x300) {
3299 if ((val & 0xFF) != 0) {
3300 unsigned L = GetLocalLabel();
3301 AddCodeLine ("clc");
3302 AddCodeLine ("adc #$%02X", (unsigned char) val);
3303 AddCodeLine ("bcc %s", LocalLabelName (L));
3304 AddCodeLine ("inx");
3305 g_defcodelabel (L);
3306 }
3307 if (val >= 0x100) {
3308 AddCodeLine ("inx");
3309 }
3310 if (val >= 0x200) {
3311 AddCodeLine ("inx");
3312 }
3313 if (val >= 0x300) {
3314 AddCodeLine ("inx");
3315 }
3316 } else if ((val & 0xFF) != 0) {
3317 AddCodeLine ("clc");
3318 AddCodeLine ("adc #$%02X", (unsigned char) val);
3319 AddCodeLine ("pha");
3320 AddCodeLine ("txa");
3321 AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3322 AddCodeLine ("tax");
3323 AddCodeLine ("pla");
3324 } else {
3325 AddCodeLine ("pha");
3326 AddCodeLine ("txa");
3327 AddCodeLine ("clc");
3328 AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3329 AddCodeLine ("tax");
3330 AddCodeLine ("pla");
3331 }
3332 }
3333 break;
3334
3335 case CF_LONG:
3336 if (val <= 255) {
3337 AddCodeLine ("ldy #$%02X", (unsigned char) val);
3338 AddCodeLine ("jsr inceaxy");
3339 } else {
3340 g_add (flags | CF_CONST, val);
3341 }
3342 break;
3343
3344 default:
3345 typeerror (flags);
3346
3347 }
3348}
3349
3350
3351
3352void g_dec (unsigned flags, unsigned long val)
3353/* Decrement the primary register by a given number */
3354{
3355 /* Don't dec by zero */
3356 if (val == 0) {
3357 return;
3358 }
3359
3360 /* Generate code for the supported types */
3361 flags &= ~CF_CONST;
3362 switch (flags & CF_TYPEMASK) {
3363
3364 case CF_CHAR:
3365 if (flags & CF_FORCECHAR) {
3366 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val <= 2) {
3367 while (val--) {
3368 AddCodeLine ("dea");
3369 }
3370 } else {
3371 AddCodeLine ("sec");
3372 AddCodeLine ("sbc #$%02X", (unsigned char)val);
3373 }
3374 break;
3375 }
3376 /* FALLTHROUGH */
3377
3378 case CF_INT:
3379 if (IS_Get (&CodeSizeFactor) < 200) {
3380 /* Use subroutines */
3381 if (val <= 8) {
3382 AddCodeLine ("jsr decax%d", (int) val);
3383 } else if (val <= 255) {
3384 AddCodeLine ("ldy #$%02X", (unsigned char) val);
3385 AddCodeLine ("jsr decaxy");
3386 } else {
3387 g_sub (flags | CF_CONST, val);
3388 }
3389 } else {
3390 /* Inline the code */
3391 if (val < 0x300) {
3392 if ((val & 0xFF) != 0) {
3393 unsigned L = GetLocalLabel();
3394 AddCodeLine ("sec");
3395 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3396 AddCodeLine ("bcs %s", LocalLabelName (L));
3397 AddCodeLine ("dex");
3398 g_defcodelabel (L);
3399 }
3400 if (val >= 0x100) {
3401 AddCodeLine ("dex");
3402 }
3403 if (val >= 0x200) {
3404 AddCodeLine ("dex");
3405 }
3406 } else {
3407 if ((val & 0xFF) != 0) {
3408 AddCodeLine ("sec");
3409 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3410 AddCodeLine ("pha");
3411 AddCodeLine ("txa");
3412 AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3413 AddCodeLine ("tax");
3414 AddCodeLine ("pla");
3415 } else {
3416 AddCodeLine ("pha");
3417 AddCodeLine ("txa");
3418 AddCodeLine ("sec");
3419 AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3420 AddCodeLine ("tax");
3421 AddCodeLine ("pla");
3422 }
3423 }
3424 }
3425 break;
3426
3427 case CF_LONG:
3428 if (val <= 255) {
3429 AddCodeLine ("ldy #$%02X", (unsigned char) val);
3430 AddCodeLine ("jsr deceaxy");
3431 } else {
3432 g_sub (flags | CF_CONST, val);
3433 }
3434 break;
3435
3436 default:
3437 typeerror (flags);
3438
3439 }
3440}
3441
3442
3443
3444/*
3445** Following are the conditional operators. They compare the TOS against
3446** the primary and put a literal 1 in the primary if the condition is
3447** true, otherwise they clear the primary register
3448*/
3449
3450
3451
3452void g_eq (unsigned flags, unsigned long val)
3453/* Test for equal */
3454{
3455 static const char* const ops[4] = {
3456 "toseqax", "toseqax", "toseqeax", "toseqeax"
3457 };
3458
3459 unsigned L;
3460
3461 /* If the right hand side is const, the lhs is not on stack but still
3462 ** in the primary register.
3463 */
3464 if (flags & CF_CONST) {
3465
3466 switch (flags & CF_TYPEMASK) {
3467
3468 case CF_CHAR:
3469 if (flags & CF_FORCECHAR) {
3470 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3471 AddCodeLine ("jsr booleq");
3472 return;
3473 }
3474 /* FALLTHROUGH */
3475
3476 case CF_INT:
3477 L = GetLocalLabel();
3478 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3479 AddCodeLine ("bne %s", LocalLabelName (L));
3480 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3481 g_defcodelabel (L);
3482 AddCodeLine ("jsr booleq");
3483 return;
3484
3485 case CF_LONG:
3486 break;
3487
3488 default:
3489 typeerror (flags);
3490 }
3491
3492 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3493 ** into the normal, non-optimized stuff. Note: The standard stuff will
3494 ** always work with ints.
3495 */
3496 flags &= ~CF_FORCECHAR;
3497 g_push (flags & ~CF_CONST, 0);
3498 }
3499
3500 /* Use long way over the stack */
3501 oper (flags, val, ops);
3502}
3503
3504
3505
3506void g_ne (unsigned flags, unsigned long val)
3507/* Test for not equal */
3508{
3509 static const char* const ops[4] = {
3510 "tosneax", "tosneax", "tosneeax", "tosneeax"
3511 };
3512
3513 unsigned L;
3514
3515 /* If the right hand side is const, the lhs is not on stack but still
3516 ** in the primary register.
3517 */
3518 if (flags & CF_CONST) {
3519
3520 switch (flags & CF_TYPEMASK) {
3521
3522 case CF_CHAR:
3523 if (flags & CF_FORCECHAR) {
3524 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3525 AddCodeLine ("jsr boolne");
3526 return;
3527 }
3528 /* FALLTHROUGH */
3529
3530 case CF_INT:
3531 L = GetLocalLabel();
3532 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3533 AddCodeLine ("bne %s", LocalLabelName (L));
3534 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3535 g_defcodelabel (L);
3536 AddCodeLine ("jsr boolne");
3537 return;
3538
3539 case CF_LONG:
3540 break;
3541
3542 default:
3543 typeerror (flags);
3544 }
3545
3546 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3547 ** into the normal, non-optimized stuff. Note: The standard stuff will
3548 ** always work with ints.
3549 */
3550 flags &= ~CF_FORCECHAR;
3551 g_push (flags & ~CF_CONST, 0);
3552 }
3553
3554 /* Use long way over the stack */
3555 oper (flags, val, ops);
3556}
3557
3558
3559
3560void g_lt (unsigned flags, unsigned long val)
3561/* Test for less than */
3562{
3563 static const char* const ops[4] = {
3564 "tosltax", "tosultax", "toslteax", "tosulteax"
3565 };
3566
3567 unsigned Label;
3568
3569 /* If the right hand side is const, the lhs is not on stack but still
3570 ** in the primary register.
3571 */
3572 if (flags & CF_CONST) {
3573
3574 /* Because the handling of the overflow flag is too complex for
3575 ** inlining, we can handle only unsigned compares, and signed
3576 ** compares against zero here.
3577 */
3578 if (flags & CF_UNSIGNED) {
3579
3580 /* Give a warning in some special cases */
3581 if (val == 0) {
3582 Warning ("Condition is never true");
3583 AddCodeLine ("jsr return0");
3584 return;
3585 }
3586
3587 /* Look at the type */
3588 switch (flags & CF_TYPEMASK) {
3589
3590 case CF_CHAR:
3591 if (flags & CF_FORCECHAR) {
3592 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3593 AddCodeLine ("jsr boolult");
3594 return;
3595 }
3596 /* FALLTHROUGH */
3597
3598 case CF_INT:
3599 /* If the low byte is zero, we must only test the high byte */
3600 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3601 if ((val & 0xFF) != 0) {
3602 unsigned L = GetLocalLabel();
3603 AddCodeLine ("bne %s", LocalLabelName (L));
3604 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3605 g_defcodelabel (L);
3606 }
3607 AddCodeLine ("jsr boolult");
3608 return;
3609
3610 case CF_LONG:
3611 /* Do a subtraction */
3612 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3613 AddCodeLine ("txa");
3614 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
3615 AddCodeLine ("lda sreg");
3616 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 16));
3617 AddCodeLine ("lda sreg+1");
3618 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 24));
3619 AddCodeLine ("jsr boolult");
3620 return;
3621
3622 default:
3623 typeerror (flags);
3624 }
3625
3626 } else if (val == 0) {
3627
3628 /* A signed compare against zero must only look at the sign bit */
3629 switch (flags & CF_TYPEMASK) {
3630
3631 case CF_CHAR:
3632 if (flags & CF_FORCECHAR) {
3633 AddCodeLine ("asl a"); /* Bit 7 -> carry */
3634 AddCodeLine ("lda #$00");
3635 AddCodeLine ("ldx #$00");
3636 AddCodeLine ("rol a");
3637 return;
3638 }
3639 /* FALLTHROUGH */
3640
3641 case CF_INT:
3642 /* Just check the high byte */
3643 AddCodeLine ("cpx #$80"); /* Bit 7 -> carry */
3644 AddCodeLine ("lda #$00");
3645 AddCodeLine ("ldx #$00");
3646 AddCodeLine ("rol a");
3647 return;
3648
3649 case CF_LONG:
3650 /* Just check the high byte */
3651 AddCodeLine ("lda sreg+1");
3652 AddCodeLine ("asl a"); /* Bit 7 -> carry */
3653 AddCodeLine ("lda #$00");
3654 AddCodeLine ("ldx #$00");
3655 AddCodeLine ("rol a");
3656 return;
3657
3658 default:
3659 typeerror (flags);
3660 }
3661
3662 } else {
3663
3664 /* Signed compare against a constant != zero */
3665 switch (flags & CF_TYPEMASK) {
3666
3667 case CF_CHAR:
3668 if (flags & CF_FORCECHAR) {
3669 Label = GetLocalLabel ();
3670 AddCodeLine ("sec");
3671 AddCodeLine ("sbc #$%02X", (unsigned char)val);
3672 AddCodeLine ("bvc %s", LocalLabelName (Label));
3673 AddCodeLine ("eor #$80");
3674 g_defcodelabel (Label);
3675 AddCodeLine ("asl a"); /* Bit 7 -> carry */
3676 AddCodeLine ("lda #$00");
3677 AddCodeLine ("ldx #$00");
3678 AddCodeLine ("rol a");
3679 return;
3680 }
3681 /* FALLTHROUGH */
3682
3683 case CF_INT:
3684 /* Do a subtraction */
3685 Label = GetLocalLabel ();
3686 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3687 AddCodeLine ("txa");
3688 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
3689 AddCodeLine ("bvc %s", LocalLabelName (Label));
3690 AddCodeLine ("eor #$80");
3691 g_defcodelabel (Label);
3692 AddCodeLine ("asl a"); /* Bit 7 -> carry */
3693 AddCodeLine ("lda #$00");
3694 AddCodeLine ("ldx #$00");
3695 AddCodeLine ("rol a");
3696 return;
3697
3698 case CF_LONG:
3699 /* This one is too costly */
3700 break;
3701
3702 default:
3703 typeerror (flags);
3704 }
3705
3706 }
3707
3708 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3709 ** into the normal, non-optimized stuff. Note: The standard stuff will
3710 ** always work with ints.
3711 */
3712 flags &= ~CF_FORCECHAR;
3713 g_push (flags & ~CF_CONST, 0);
3714 }
3715
3716 /* Use long way over the stack */
3717 oper (flags, val, ops);
3718}
3719
3720
3721
3722void g_le (unsigned flags, unsigned long val)
3723/* Test for less than or equal to */
3724{
3725 static const char* const ops[4] = {
3726 "tosleax", "tosuleax", "tosleeax", "tosuleeax"
3727 };
3728
3729
3730 /* If the right hand side is const, the lhs is not on stack but still
3731 ** in the primary register.
3732 */
3733 if (flags & CF_CONST) {
3734
3735 /* Look at the type */
3736 switch (flags & CF_TYPEMASK) {
3737
3738 case CF_CHAR:
3739 if (flags & CF_FORCECHAR) {
3740 if (flags & CF_UNSIGNED) {
3741 /* Unsigned compare */
3742 if (val < 0xFF) {
3743 /* Use < instead of <= because the former gives
3744 ** better code on the 6502 than the latter.
3745 */
3746 g_lt (flags, val+1);
3747 } else {
3748 /* Always true */
3749 Warning ("Condition is always true");
3750 AddCodeLine ("jsr return1");
3751 }
3752 } else {
3753 /* Signed compare */
3754 if ((long) val < 0x7F) {
3755 /* Use < instead of <= because the former gives
3756 ** better code on the 6502 than the latter.
3757 */
3758 g_lt (flags, val+1);
3759 } else {
3760 /* Always true */
3761 Warning ("Condition is always true");
3762 AddCodeLine ("jsr return1");
3763 }
3764 }
3765 return;
3766 }
3767 /* FALLTHROUGH */
3768
3769 case CF_INT:
3770 if (flags & CF_UNSIGNED) {
3771 /* Unsigned compare */
3772 if (val < 0xFFFF) {
3773 /* Use < instead of <= because the former gives
3774 ** better code on the 6502 than the latter.
3775 */
3776 g_lt (flags, val+1);
3777 } else {
3778 /* Always true */
3779 Warning ("Condition is always true");
3780 AddCodeLine ("jsr return1");
3781 }
3782 } else {
3783 /* Signed compare */
3784 if ((long) val < 0x7FFF) {
3785 g_lt (flags, val+1);
3786 } else {
3787 /* Always true */
3788 Warning ("Condition is always true");
3789 AddCodeLine ("jsr return1");
3790 }
3791 }
3792 return;
3793
3794 case CF_LONG:
3795 if (flags & CF_UNSIGNED) {
3796 /* Unsigned compare */
3797 if (val < 0xFFFFFFFF) {
3798 /* Use < instead of <= because the former gives
3799 ** better code on the 6502 than the latter.
3800 */
3801 g_lt (flags, val+1);
3802 } else {
3803 /* Always true */
3804 Warning ("Condition is always true");
3805 AddCodeLine ("jsr return1");
3806 }
3807 } else {
3808 /* Signed compare */
3809 if ((long) val < 0x7FFFFFFF) {
3810 g_lt (flags, val+1);
3811 } else {
3812 /* Always true */
3813 Warning ("Condition is always true");
3814 AddCodeLine ("jsr return1");
3815 }
3816 }
3817 return;
3818
3819 default:
3820 typeerror (flags);
3821 }
3822
3823 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3824 ** into the normal, non-optimized stuff. Note: The standard stuff will
3825 ** always work with ints.
3826 */
3827 flags &= ~CF_FORCECHAR;
3828 g_push (flags & ~CF_CONST, 0);
3829 }
3830
3831 /* Use long way over the stack */
3832 oper (flags, val, ops);
3833}
3834
3835
3836
3837void g_gt (unsigned flags, unsigned long val)
3838/* Test for greater than */
3839{
3840 static const char* const ops[4] = {
3841 "tosgtax", "tosugtax", "tosgteax", "tosugteax"
3842 };
3843
3844
3845 /* If the right hand side is const, the lhs is not on stack but still
3846 ** in the primary register.
3847 */
3848 if (flags & CF_CONST) {
3849
3850 /* Look at the type */
3851 switch (flags & CF_TYPEMASK) {
3852
3853 case CF_CHAR:
3854 if (flags & CF_FORCECHAR) {
3855 if (flags & CF_UNSIGNED) {
3856 if (val == 0) {
3857 /* If we have a compare > 0, we will replace it by
3858 ** != 0 here, since both are identical but the
3859 ** latter is easier to optimize.
3860 */
3861 g_ne (flags, val);
3862 } else if (val < 0xFF) {
3863 /* Use >= instead of > because the former gives
3864 ** better code on the 6502 than the latter.
3865 */
3866 g_ge (flags, val+1);
3867 } else {
3868 /* Never true */
3869 Warning ("Condition is never true");
3870 AddCodeLine ("jsr return0");
3871 }
3872 } else {
3873 if ((long) val < 0x7F) {
3874 /* Use >= instead of > because the former gives
3875 ** better code on the 6502 than the latter.
3876 */
3877 g_ge (flags, val+1);
3878 } else {
3879 /* Never true */
3880 Warning ("Condition is never true");
3881 AddCodeLine ("jsr return0");
3882 }
3883 }
3884 return;
3885 }
3886 /* FALLTHROUGH */
3887
3888 case CF_INT:
3889 if (flags & CF_UNSIGNED) {
3890 /* Unsigned compare */
3891 if (val == 0) {
3892 /* If we have a compare > 0, we will replace it by
3893 ** != 0 here, since both are identical but the latter
3894 ** is easier to optimize.
3895 */
3896 g_ne (flags, val);
3897 } else if (val < 0xFFFF) {
3898 /* Use >= instead of > because the former gives better
3899 ** code on the 6502 than the latter.
3900 */
3901 g_ge (flags, val+1);
3902 } else {
3903 /* Never true */
3904 Warning ("Condition is never true");
3905 AddCodeLine ("jsr return0");
3906 }
3907 } else {
3908 /* Signed compare */
3909 if ((long) val < 0x7FFF) {
3910 g_ge (flags, val+1);
3911 } else {
3912 /* Never true */
3913 Warning ("Condition is never true");
3914 AddCodeLine ("jsr return0");
3915 }
3916 }
3917 return;
3918
3919 case CF_LONG:
3920 if (flags & CF_UNSIGNED) {
3921 /* Unsigned compare */
3922 if (val == 0) {
3923 /* If we have a compare > 0, we will replace it by
3924 ** != 0 here, since both are identical but the latter
3925 ** is easier to optimize.
3926 */
3927 g_ne (flags, val);
3928 } else if (val < 0xFFFFFFFF) {
3929 /* Use >= instead of > because the former gives better
3930 ** code on the 6502 than the latter.
3931 */
3932 g_ge (flags, val+1);
3933 } else {
3934 /* Never true */
3935 Warning ("Condition is never true");
3936 AddCodeLine ("jsr return0");
3937 }
3938 } else {
3939 /* Signed compare */
3940 if ((long) val < 0x7FFFFFFF) {
3941 g_ge (flags, val+1);
3942 } else {
3943 /* Never true */
3944 Warning ("Condition is never true");
3945 AddCodeLine ("jsr return0");
3946 }
3947 }
3948 return;
3949
3950 default:
3951 typeerror (flags);
3952 }
3953
3954 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3955 ** into the normal, non-optimized stuff. Note: The standard stuff will
3956 ** always work with ints.
3957 */
3958 flags &= ~CF_FORCECHAR;
3959 g_push (flags & ~CF_CONST, 0);
3960 }
3961
3962 /* Use long way over the stack */
3963 oper (flags, val, ops);
3964}
3965
3966
3967
3968void g_ge (unsigned flags, unsigned long val)
3969/* Test for greater than or equal to */
3970{
3971 static const char* const ops[4] = {
3972 "tosgeax", "tosugeax", "tosgeeax", "tosugeeax"
3973 };
3974
3975 unsigned Label;
3976
3977
3978 /* If the right hand side is const, the lhs is not on stack but still
3979 ** in the primary register.
3980 */
3981 if (flags & CF_CONST) {
3982
3983 /* Because the handling of the overflow flag is too complex for
3984 ** inlining, we can handle only unsigned compares, and signed
3985 ** compares against zero here.
3986 */
3987 if (flags & CF_UNSIGNED) {
3988
3989 /* Give a warning in some special cases */
3990 if (val == 0) {
3991 Warning ("Condition is always true");
3992 AddCodeLine ("jsr return1");
3993 return;
3994 }
3995
3996 /* Look at the type */
3997 switch (flags & CF_TYPEMASK) {
3998
3999 case CF_CHAR:
4000 if (flags & CF_FORCECHAR) {
4001 /* Do a subtraction. Condition is true if carry set */
4002 AddCodeLine ("cmp #$%02X", (unsigned char)val);
4003 AddCodeLine ("lda #$00");
4004 AddCodeLine ("ldx #$00");
4005 AddCodeLine ("rol a");
4006 return;
4007 }
4008 /* FALLTHROUGH */
4009
4010 case CF_INT:
4011 /* Do a subtraction. Condition is true if carry set */
4012 AddCodeLine ("cmp #$%02X", (unsigned char)val);
4013 AddCodeLine ("txa");
4014 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
4015 AddCodeLine ("lda #$00");
4016 AddCodeLine ("ldx #$00");
4017 AddCodeLine ("rol a");
4018 return;
4019
4020 case CF_LONG:
4021 /* Do a subtraction. Condition is true if carry set */
4022 AddCodeLine ("cmp #$%02X", (unsigned char)val);
4023 AddCodeLine ("txa");
4024 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
4025 AddCodeLine ("lda sreg");
4026 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 16));
4027 AddCodeLine ("lda sreg+1");
4028 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 24));
4029 AddCodeLine ("lda #$00");
4030 AddCodeLine ("ldx #$00");
4031 AddCodeLine ("rol a");
4032 return;
4033
4034 default:
4035 typeerror (flags);
4036 }
4037
4038 } else if (val == 0) {
4039
4040 /* A signed compare against zero must only look at the sign bit */
4041 switch (flags & CF_TYPEMASK) {
4042
4043 case CF_CHAR:
4044 if (flags & CF_FORCECHAR) {
4045 AddCodeLine ("tax");
4046 AddCodeLine ("jsr boolge");
4047 return;
4048 }
4049 /* FALLTHROUGH */
4050
4051 case CF_INT:
4052 /* Just test the high byte */
4053 AddCodeLine ("txa");
4054 AddCodeLine ("jsr boolge");
4055 return;
4056
4057 case CF_LONG:
4058 /* Just test the high byte */
4059 AddCodeLine ("lda sreg+1");
4060 AddCodeLine ("jsr boolge");
4061 return;
4062
4063 default:
4064 typeerror (flags);
4065 }
4066
4067 } else {
4068
4069 /* Signed compare against a constant != zero */
4070 switch (flags & CF_TYPEMASK) {
4071
4072 case CF_CHAR:
4073 if (flags & CF_FORCECHAR) {
4074 Label = GetLocalLabel ();
4075 AddCodeLine ("sec");
4076 AddCodeLine ("sbc #$%02X", (unsigned char)val);
4077 AddCodeLine ("bvs %s", LocalLabelName (Label));
4078 AddCodeLine ("eor #$80");
4079 g_defcodelabel (Label);
4080 AddCodeLine ("asl a"); /* Bit 7 -> carry */
4081 AddCodeLine ("lda #$00");
4082 AddCodeLine ("ldx #$00");
4083 AddCodeLine ("rol a");
4084 return;
4085 }
4086 /* FALLTHROUGH */
4087
4088 case CF_INT:
4089 /* Do a subtraction */
4090 Label = GetLocalLabel ();
4091 AddCodeLine ("cmp #$%02X", (unsigned char)val);
4092 AddCodeLine ("txa");
4093 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
4094 AddCodeLine ("bvs %s", LocalLabelName (Label));
4095 AddCodeLine ("eor #$80");
4096 g_defcodelabel (Label);
4097 AddCodeLine ("asl a"); /* Bit 7 -> carry */
4098 AddCodeLine ("lda #$00");
4099 AddCodeLine ("ldx #$00");
4100 AddCodeLine ("rol a");
4101 return;
4102
4103 case CF_LONG:
4104 /* This one is too costly */
4105 break;
4106
4107 default:
4108 typeerror (flags);
4109 }
4110 }
4111
4112 /* If we go here, we didn't emit code. Push the lhs on stack and fall
4113 ** into the normal, non-optimized stuff. Note: The standard stuff will
4114 ** always work with ints.
4115 */
4116 flags &= ~CF_FORCECHAR;
4117 g_push (flags & ~CF_CONST, 0);
4118 }
4119
4120 /* Use long way over the stack */
4121 oper (flags, val, ops);
4122}
4123
4124
4125
4126/*****************************************************************************/
4127/* Allocating static storage */
4128/*****************************************************************************/
4129
4130
4131
4132void g_res (unsigned n)
4133/* Reserve static storage, n bytes */
4134{
4135 AddDataLine ("\t.res\t%u,$00", n);
4136}
4137
4138
4139
4140void g_defdata (unsigned flags, unsigned long val, long offs)
4141/* Define data with the size given in flags */
4142{
4143 if (flags & CF_CONST) {
4144
4145 /* Numeric constant */
4146 switch (flags & CF_TYPEMASK) {
4147
4148 case CF_CHAR:
4149 AddDataLine ("\t.byte\t$%02lX", val & 0xFF);
4150 break;
4151
4152 case CF_INT:
4153 AddDataLine ("\t.word\t$%04lX", val & 0xFFFF);
4154 break;
4155
4156 case CF_LONG:
4157 AddDataLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
4158 break;
4159
4160 default:
4161 typeerror (flags);
4162 break;
4163
4164 }
4165
4166 } else {
4167
4168 /* Create the correct label name */
4169 const char* Label = GetLabelName (flags, val, offs);
4170
4171 /* Labels are always 16 bit */
4172 AddDataLine ("\t.addr\t%s", Label);
4173
4174 }
4175}
4176
4177
4178
4179void g_defbytes (const void* Bytes, unsigned Count)
4180/* Output a row of bytes as a constant */
4181{
4182 unsigned Chunk;
4183 char Buf [128];
4184 char* B;
4185
4186 /* Cast the buffer pointer */
4187 const unsigned char* Data = (const unsigned char*) Bytes;
4188
4189 /* Output the stuff */
4190 while (Count) {
4191
4192 /* How many go into this line? */
4193 if ((Chunk = Count) > 16) {
4194 Chunk = 16;
4195 }
4196 Count -= Chunk;
4197
4198 /* Output one line */
4199 strcpy (Buf, "\t.byte\t");
4200 B = Buf + 7;
4201 do {
4202 B += sprintf (B, "$%02X", *Data++);
4203 if (--Chunk) {
4204 *B++ = ',';
4205 }
4206 } while (Chunk);
4207
4208 /* Output the line */
4209 AddDataLine ("%s", Buf);
4210 }
4211}
4212
4213
4214
4215void g_zerobytes (unsigned Count)
4216/* Output Count bytes of data initialized with zero */
4217{
4218 if (Count > 0) {
4219 AddDataLine ("\t.res\t%u,$00", Count);
4220 }
4221}
4222
4223
4224
4225void g_initregister (unsigned Label, unsigned Reg, unsigned Size)
4226/* Initialize a register variable from static initialization data */
4227{
4228 /* Register variables do always have less than 128 bytes */
4229 unsigned CodeLabel = GetLocalLabel ();
4230 AddCodeLine ("ldx #$%02X", (unsigned char) (Size - 1));
4231 g_defcodelabel (CodeLabel);
4232 AddCodeLine ("lda %s,x", GetLabelName (CF_STATIC, Label, 0));
4233 AddCodeLine ("sta %s,x", GetLabelName (CF_REGVAR, Reg, 0));
4234 AddCodeLine ("dex");
4235 AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4236}
4237
4238
4239
4240void g_initauto (unsigned Label, unsigned Size)
4241/* Initialize a local variable at stack offset zero from static data */
4242{
4243 unsigned CodeLabel = GetLocalLabel ();
4244
4245 CheckLocalOffs (Size);
4246 if (Size <= 128) {
4247 AddCodeLine ("ldy #$%02X", Size-1);
4248 g_defcodelabel (CodeLabel);
4249 AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, Label, 0));
4250 AddCodeLine ("sta (sp),y");
4251 AddCodeLine ("dey");
4252 AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4253 } else if (Size <= 256) {
4254 AddCodeLine ("ldy #$00");
4255 g_defcodelabel (CodeLabel);
4256 AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, Label, 0));
4257 AddCodeLine ("sta (sp),y");
4258 AddCodeLine ("iny");
4259 AddCmpCodeIfSizeNot256 ("cpy #$%02X", Size);
4260 AddCodeLine ("bne %s", LocalLabelName (CodeLabel));
4261 }
4262}
4263
4264
4265
4266void g_initstatic (unsigned InitLabel, unsigned VarLabel, unsigned Size)
4267/* Initialize a static local variable from static initialization data */
4268{
4269 if (Size <= 128) {
4270 unsigned CodeLabel = GetLocalLabel ();
4271 AddCodeLine ("ldy #$%02X", Size-1);
4272 g_defcodelabel (CodeLabel);
4273 AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, InitLabel, 0));
4274 AddCodeLine ("sta %s,y", GetLabelName (CF_STATIC, VarLabel, 0));
4275 AddCodeLine ("dey");
4276 AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4277 } else if (Size <= 256) {
4278 unsigned CodeLabel = GetLocalLabel ();
4279 AddCodeLine ("ldy #$00");
4280 g_defcodelabel (CodeLabel);
4281 AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, InitLabel, 0));
4282 AddCodeLine ("sta %s,y", GetLabelName (CF_STATIC, VarLabel, 0));
4283 AddCodeLine ("iny");
4284 AddCmpCodeIfSizeNot256 ("cpy #$%02X", Size);
4285 AddCodeLine ("bne %s", LocalLabelName (CodeLabel));
4286 } else {
4287 /* Use the easy way here: memcpy() */
4288 g_getimmed (CF_STATIC, VarLabel, 0);
4289 AddCodeLine ("jsr pushax");
4290 g_getimmed (CF_STATIC, InitLabel, 0);
4291 AddCodeLine ("jsr pushax");
4292 g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, Size, 0);
4293 AddCodeLine ("jsr %s", GetLabelName (CF_EXTERNAL, (uintptr_t) "memcpy", 0));
4294 }
4295}
4296
4297
4298
4299/*****************************************************************************/
4300/* Switch statement */
4301/*****************************************************************************/
4302
4303
4304
4305void g_switch (Collection* Nodes, unsigned DefaultLabel, unsigned Depth)
4306/* Generate code for a switch statement */
4307{
4308 unsigned NextLabel = 0;
4309 unsigned I;
4310
4311 /* Setup registers and determine which compare insn to use */
4312 const char* Compare;
4313 switch (Depth) {
4314 case 1:
4315 Compare = "cmp #$%02X";
4316 break;
4317 case 2:
4318 Compare = "cpx #$%02X";
4319 break;
4320 case 3:
4321 AddCodeLine ("ldy sreg");
4322 Compare = "cpy #$%02X";
4323 break;
4324 case 4:
4325 AddCodeLine ("ldy sreg+1");
4326 Compare = "cpy #$%02X";
4327 break;
4328 default:
4329 Internal ("Invalid depth in g_switch: %u", Depth);
4330 }
4331
4332 /* Walk over all nodes */
4333 for (I = 0; I < CollCount (Nodes); ++I) {
4334
4335 /* Get the next case node */
4336 CaseNode* N = CollAtUnchecked (Nodes, I);
4337
4338 /* If we have a next label, define it */
4339 if (NextLabel) {
4340 g_defcodelabel (NextLabel);
4341 NextLabel = 0;
4342 }
4343
4344 /* Do the compare */
4345 AddCodeLine (Compare, CN_GetValue (N));
4346
4347 /* If this is the last level, jump directly to the case code if found */
4348 if (Depth == 1) {
4349
4350 /* Branch if equal */
4351 g_falsejump (0, CN_GetLabel (N));
4352
4353 } else {
4354
4355 /* Determine the next label */
4356 if (I == CollCount (Nodes) - 1) {
4357 /* Last node means not found */
4358 g_truejump (0, DefaultLabel);
4359 } else {
4360 /* Jump to the next check */
4361 NextLabel = GetLocalLabel ();
4362 g_truejump (0, NextLabel);
4363 }
4364
4365 /* Check the next level */
4366 g_switch (N->Nodes, DefaultLabel, Depth-1);
4367
4368 }
4369 }
4370
4371 /* If we go here, we haven't found the label */
4372 g_jump (DefaultLabel);
4373}
4374
4375
4376
4377/*****************************************************************************/
4378/* User supplied assembler code */
4379/*****************************************************************************/
4380
4381
4382
4383void g_asmcode (struct StrBuf* B)
4384/* Output one line of assembler code. */
4385{
4386 AddCodeLine ("%.*s", (int) SB_GetLen (B), SB_GetConstBuf (B));
4387}
4388