]> git.sur5r.net Git - cc65/blob - src/cc65/codeent.c
14bab06393a42336caabc71ffa88a3b8d289de30
[cc65] / src / cc65 / codeent.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 codeent.c                                 */
4 /*                                                                           */
5 /*                            Code segment entry                             */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001-2002 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdlib.h>
37 #include <string.h>
38
39 /* common */
40 #include "chartype.h"
41 #include "check.h"
42 #include "xmalloc.h"
43 #include "xsprintf.h"
44
45 /* cc65 */
46 #include "codeinfo.h"
47 #include "error.h"
48 #include "global.h"
49 #include "codelab.h"
50 #include "opcodes.h"
51 #include "codeent.h"
52
53
54
55 /*****************************************************************************/
56 /*                                   Data                                    */
57 /*****************************************************************************/
58
59
60
61 /* Empty argument */
62 static char EmptyArg[] = "";
63
64
65
66 /*****************************************************************************/
67 /*                             Helper functions                              */
68 /*****************************************************************************/
69
70
71
72 static void FreeArg (char* Arg)
73 /* Free a code entry argument */
74 {
75     if (Arg != EmptyArg) {
76         xfree (Arg);
77     }
78 }
79
80
81
82 static char* GetArgCopy (const char* Arg)
83 /* Create an argument copy for assignment */
84 {
85     if (Arg && Arg[0] != '\0') {
86         /* Create a copy */
87         return xstrdup (Arg);
88     } else {
89         /* Use the empty argument string */
90         return EmptyArg;
91     }
92 }
93
94
95
96 static int NumArg (const char* Arg, unsigned long* Num)
97 /* If the given argument is numerical, convert it and return true. Otherwise
98  * set Num to zero and return false.
99  */
100 {
101     char* End;
102     unsigned long Val;
103
104     /* Determine the base */
105     int Base = 10;
106     if (*Arg == '$') {
107         ++Arg;
108         Base = 16;
109     } else if (*Arg == '%') {
110         ++Arg;
111         Base = 2;
112     }
113
114     /* Convert the value. strtol is not exactly what we want here, but it's
115      * cheap and may be replaced by something fancier later.
116      */
117     Val = strtoul (Arg, &End, Base);
118
119     /* Check if the conversion was successful */
120     if (*End != '\0') {
121
122         /* Could not convert */
123         *Num = 0;
124         return 0;
125
126     } else {
127
128         /* Conversion ok */
129         *Num = Val;
130         return 1;
131
132     }
133 }
134
135
136
137 static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D)
138 /* Set the Use and Chg in E */
139 {
140     const ZPInfo* Info;
141
142     /* If this is a subroutine call, or a jump to an external function,
143      * lookup the information about this function and use it. The jump itself
144      * does not change any registers, so we don't need to use the data from D.
145      */
146     if ((E->Info & (OF_BRA | OF_CALL)) != 0 && E->JumpTo == 0) {
147         /* A subroutine call or jump to external symbol (function exit) */
148         GetFuncInfo (E->Arg, &E->Use, &E->Chg);
149     } else {
150         /* Some other instruction. Use the values from the opcode description
151          * plus addressing mode info.
152          */
153         E->Use = D->Use | GetAMUseInfo (E->AM);
154         E->Chg = D->Chg;
155
156         /* Check for special zero page registers used */
157         switch (E->AM) {
158
159             case AM65_ACC:
160                 if (E->OPC == OP65_ASL || E->OPC == OP65_DEC ||
161                     E->OPC == OP65_INC || E->OPC == OP65_LSR ||
162                     E->OPC == OP65_ROL || E->OPC == OP65_ROR) {
163                     /* A is changed by these insns */
164                     E->Chg |= REG_A;
165                 }
166                 break;
167
168             case AM65_ZP:
169             case AM65_ABS:
170             /* Be conservative: */
171             case AM65_ZPX:
172             case AM65_ABSX:
173             case AM65_ABSY:
174                 Info = GetZPInfo (E->Arg);
175                 if (Info && Info->ByteUse != REG_NONE) {
176                     if (E->OPC == OP65_ASL || E->OPC == OP65_DEC ||
177                         E->OPC == OP65_INC || E->OPC == OP65_LSR ||
178                         E->OPC == OP65_ROL || E->OPC == OP65_ROR ||
179                         E->OPC == OP65_TRB || E->OPC == OP65_TSB) {
180                         /* The zp loc is both, input and output */
181                         E->Chg |= Info->ByteUse;
182                         E->Use |= Info->ByteUse;
183                     } else if ((E->Info & OF_STORE) != 0) {
184                         /* Just output */
185                         E->Chg |= Info->ByteUse;
186                     } else {
187                         /* Input only */
188                         E->Use |= Info->ByteUse;
189                     }
190                 }
191                 break;
192
193             case AM65_ZPX_IND:
194             case AM65_ZP_INDY:
195             case AM65_ZP_IND:
196                 Info = GetZPInfo (E->Arg);
197                 if (Info && Info->ByteUse != REG_NONE) {
198                     /* These addressing modes will never change the zp loc */
199                     E->Use |= Info->WordUse;
200                 }
201                 break;
202
203             default:
204                 /* Keep gcc silent */
205                 break;
206         }
207     }
208 }
209
210
211
212 /*****************************************************************************/
213 /*                                   Code                                    */
214 /*****************************************************************************/
215
216
217
218 const char* MakeHexArg (unsigned Num)
219 /* Convert Num into a string in the form $XY, suitable for passing it as an
220  * argument to NewCodeEntry, and return a pointer to the string.
221  * BEWARE: The function returns a pointer to a static buffer, so the value is
222  * gone if you call it twice (and apart from that it's not thread and signal
223  * safe).
224  */
225 {
226     static char Buf[16];
227     xsprintf (Buf, sizeof (Buf), "$%02X", (char) Num);
228     return Buf;
229 }
230
231
232
233 CodeEntry* NewCodeEntry (opc_t OPC, am_t AM, const char* Arg,
234                          CodeLabel* JumpTo, LineInfo* LI)
235 /* Create a new code entry, initialize and return it */
236 {
237     /* Get the opcode description */
238     const OPCDesc* D = GetOPCDesc (OPC);
239
240     /* Allocate memory */
241     CodeEntry* E = xmalloc (sizeof (CodeEntry));
242
243     /* Initialize the fields */
244     E->OPC    = D->OPC;
245     E->AM     = AM;
246     E->Arg    = GetArgCopy (Arg);
247     E->Flags  = NumArg (E->Arg, &E->Num)? CEF_NUMARG : 0;
248     E->Info   = D->Info;
249     E->Size   = GetInsnSize (E->OPC, E->AM);
250     E->JumpTo = JumpTo;
251     E->LI     = UseLineInfo (LI);
252     E->RI     = 0;
253     SetUseChgInfo (E, D);
254     InitCollection (&E->Labels);
255
256     /* If we have a label given, add this entry to the label */
257     if (JumpTo) {
258         CollAppend (&JumpTo->JumpFrom, E);
259     }
260
261     /* Return the initialized struct */
262     return E;
263 }
264
265
266
267 void FreeCodeEntry (CodeEntry* E)
268 /* Free the given code entry */
269 {
270     /* Free the string argument if we have one */
271     FreeArg (E->Arg);
272
273     /* Cleanup the collection */
274     DoneCollection (&E->Labels);
275
276     /* Release the line info */
277     ReleaseLineInfo (E->LI);
278
279     /* Delete the register info */
280     CE_FreeRegInfo (E);
281
282     /* Free the entry */
283     xfree (E);
284 }
285
286
287
288 void CE_ReplaceOPC (CodeEntry* E, opc_t OPC)
289 /* Replace the opcode of the instruction. This will also replace related info,
290  * Size, Use and Chg, but it will NOT update any arguments or labels.
291  */
292 {
293     /* Get the opcode descriptor */
294     const OPCDesc* D = GetOPCDesc (OPC);
295
296     /* Replace the opcode */
297     E->OPC  = OPC;
298     E->Info = D->Info;
299     E->Size = GetInsnSize (E->OPC, E->AM);
300     SetUseChgInfo (E, D);
301 }
302
303
304
305 int CodeEntriesAreEqual (const CodeEntry* E1, const CodeEntry* E2)
306 /* Check if both code entries are equal */
307 {
308     return E1->OPC == E2->OPC && E1->AM == E2->AM && strcmp (E1->Arg, E2->Arg) == 0;
309 }
310
311
312
313 void CE_AttachLabel (CodeEntry* E, CodeLabel* L)
314 /* Attach the label to the entry */
315 {
316     /* Add it to the entries label list */
317     CollAppend (&E->Labels, L);
318
319     /* Tell the label about it's owner */
320     L->Owner = E;
321 }
322
323
324
325 void CE_MoveLabel (CodeLabel* L, CodeEntry* E)
326 /* Move the code label L from it's former owner to the code entry E. */
327 {
328     /* Delete the label from the owner */
329     CollDeleteItem (&L->Owner->Labels, L);
330
331     /* Set the new owner */
332     CollAppend (&E->Labels, L);
333     L->Owner = E;
334 }
335
336
337
338 void CE_SetNumArg (CodeEntry* E, long Num)
339 /* Set a new numeric argument for the given code entry that must already
340  * have a numeric argument.
341  */
342 {
343     char Buf[16];
344
345     /* Check that the entry has a numerical argument */
346     CHECK (E->Flags & CEF_NUMARG);
347
348     /* Make the new argument string */
349     if (E->Size == 2) {
350         Num &= 0xFF;
351         xsprintf (Buf, sizeof (Buf), "$%02X", (unsigned) Num);
352     } else if (E->Size == 3) {
353         Num &= 0xFFFF;
354         xsprintf (Buf, sizeof (Buf), "$%04X", (unsigned) Num);
355     } else {
356         Internal ("Invalid instruction size in CE_SetNumArg");
357     }
358
359     /* Free the old argument */
360     FreeArg (E->Arg);
361
362     /* Assign the new one */
363     E->Arg = GetArgCopy (Buf);
364
365     /* Use the new numerical value */
366     E->Num = Num;
367 }
368
369
370
371 int CE_KnownImm (const CodeEntry* E)
372 /* Return true if the argument of E is a known immediate value */
373 {
374     return (E->AM == AM65_IMM && (E->Flags & CEF_NUMARG) != 0);
375 }
376
377
378
379 void CE_FreeRegInfo (CodeEntry* E)
380 /* Free an existing register info struct */
381 {
382     if (E->RI) {
383         FreeRegInfo (E->RI);
384         E->RI = 0;
385     }
386 }
387
388
389
390 void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
391 /* Generate register info for this instruction. If an old info exists, it is
392  * overwritten.
393  */
394 {
395     /* Pointers to the register contents */
396     RegContents* In;
397     RegContents* Out;
398
399     /* Function register usage */
400     unsigned short Use, Chg;
401
402     /* If we don't have a register info struct, allocate one. */
403     if (E->RI == 0) {
404         E->RI = NewRegInfo (InputRegs);
405     } else {
406         if (InputRegs) {
407             E->RI->In  = *InputRegs;
408         } else {
409             RC_Invalidate (&E->RI->In);
410         }
411         E->RI->Out2 = E->RI->Out = E->RI->In;
412     }
413
414     /* Get pointers to the register contents */
415     In  = &E->RI->In;
416     Out = &E->RI->Out;
417
418     /* Handle the different instructions */
419     switch (E->OPC) {
420
421         case OP65_ADC:
422             /* We don't know the value of the carry, so the result is
423              * always unknown.
424              */
425             Out->RegA = -1;
426             break;
427
428         case OP65_AND:
429             if (In->RegA >= 0) {
430                 if (CE_KnownImm (E)) {
431                     Out->RegA = In->RegA & (short) E->Num;
432                 } else if (E->AM == AM65_ZP) {
433                     switch (GetKnownReg (E->Use, In)) {
434                         case REG_TMP1:
435                             Out->RegA = In->RegA & In->Tmp1;
436                             break;
437                         case REG_SREG_LO:
438                             Out->RegA = In->RegA & In->SRegLo;
439                             break;
440                         case REG_SREG_HI:
441                             Out->RegA = In->RegA & In->SRegHi;
442                             break;
443                         default:
444                             Out->RegA = -1;
445                             break;
446                     }
447                 } else {
448                     Out->RegA = -1;
449                 }
450             }
451             break;
452
453         case OP65_ASL:
454             if (E->AM == AM65_ACC && In->RegA >= 0) {
455                 Out->RegA = (In->RegA << 1) & 0xFF;
456             } else if (E->AM == AM65_ZP) {
457                 switch (GetKnownReg (E->Chg, In)) {
458                     case REG_TMP1:
459                         Out->Tmp1 = (In->Tmp1 << 1) & 0xFF;
460                         break;
461                     case REG_SREG_LO:
462                         Out->SRegLo = (In->SRegLo << 1) & 0xFF;
463                         break;
464                     case REG_SREG_HI:
465                         Out->SRegHi = (In->SRegHi << 1) & 0xFF;
466                         break;
467                 }
468             } else if (E->AM == AM65_ZPX) {
469                 /* Invalidates all ZP registers */
470                 RC_InvalidateZP (Out);
471             }
472             break;
473
474         case OP65_BCC:
475             break;
476
477         case OP65_BCS:
478             break;
479
480         case OP65_BEQ:
481             break;
482
483         case OP65_BIT:
484             break;
485
486         case OP65_BMI:
487             break;
488
489         case OP65_BNE:
490             break;
491
492         case OP65_BPL:
493             break;
494
495         case OP65_BRA:
496             break;
497
498         case OP65_BRK:
499             break;
500
501         case OP65_BVC:
502             break;
503
504         case OP65_BVS:
505             break;
506
507         case OP65_CLC:
508             break;
509
510         case OP65_CLD:
511             break;
512
513         case OP65_CLI:
514             break;
515
516         case OP65_CLV:
517             break;
518
519         case OP65_CMP:
520             break;
521
522         case OP65_CPX:
523             break;
524
525         case OP65_CPY:
526             break;
527
528         case OP65_DEA:
529             if (In->RegA >= 0) {
530                 Out->RegA = (In->RegA - 1) & 0xFF;
531             }
532             break;
533
534         case OP65_DEC:
535             if (E->AM == AM65_ACC && In->RegA >= 0) {
536                 Out->RegA = (In->RegA - 1) & 0xFF;
537             } else if (E->AM == AM65_ZP) {
538                 switch (GetKnownReg (E->Chg, In)) {
539                     case REG_TMP1:
540                         Out->Tmp1 = (In->Tmp1 - 1) & 0xFF;
541                         break;
542                     case REG_SREG_LO:
543                         Out->SRegLo = (In->SRegLo - 1) & 0xFF;
544                         break;
545                     case REG_SREG_HI:
546                         Out->SRegHi = (In->SRegHi - 1) & 0xFF;
547                         break;
548                 }
549             } else if (E->AM == AM65_ZPX) {
550                 /* Invalidates all ZP registers */
551                 RC_InvalidateZP (Out);
552             }
553             break;
554
555         case OP65_DEX:
556             if (In->RegX >= 0) {
557                 Out->RegX = (In->RegX - 1) & 0xFF;
558             }
559             break;
560
561         case OP65_DEY:
562             if (In->RegY >= 0) {
563                 Out->RegY = (In->RegY - 1) & 0xFF;
564             }
565             break;
566
567         case OP65_EOR:
568             if (In->RegA >= 0) {
569                 if (CE_KnownImm (E)) {
570                     Out->RegA = In->RegA ^ (short) E->Num;
571                 } else if (E->AM == AM65_ZP) {
572                     switch (GetKnownReg (E->Use, In)) {
573                         case REG_TMP1:
574                             Out->RegA = In->RegA ^ In->Tmp1;
575                             break;
576                         case REG_SREG_LO:
577                             Out->RegA = In->RegA ^ In->SRegLo;
578                             break;
579                         case REG_SREG_HI:
580                             Out->RegA = In->RegA ^ In->SRegHi;
581                             break;
582                         default:
583                             Out->RegA = -1;
584                             break;
585                     }
586                 } else {
587                     Out->RegA = -1;
588                 }
589             }
590             break;
591
592         case OP65_INA:
593             if (In->RegA >= 0) {
594                 Out->RegA = (In->RegA + 1) & 0xFF;
595             }
596             break;
597
598         case OP65_INC:
599             if (E->AM == AM65_ACC && In->RegA >= 0) {
600                 Out->RegA = (In->RegA + 1) & 0xFF;
601             } else if (E->AM == AM65_ZP) {
602                 switch (GetKnownReg (E->Chg, In)) {
603                     case REG_TMP1:
604                         Out->Tmp1 = (In->Tmp1 + 1) & 0xFF;
605                         break;
606                     case REG_SREG_LO:
607                         Out->SRegLo = (In->SRegLo + 1) & 0xFF;
608                         break;
609                     case REG_SREG_HI:
610                         Out->SRegHi = (In->SRegHi + 1) & 0xFF;
611                         break;
612                 }
613             } else if (E->AM == AM65_ZPX) {
614                 /* Invalidates all ZP registers */
615                 RC_InvalidateZP (Out);
616             }
617             break;
618
619         case OP65_INX:
620             if (In->RegX >= 0) {
621                 Out->RegX = (In->RegX + 1) & 0xFF;
622             }
623             break;
624
625         case OP65_INY:
626             if (In->RegY >= 0) {
627                 Out->RegY = (In->RegY + 1) & 0xFF;
628             }
629             break;
630
631         case OP65_JCC:
632             break;
633
634         case OP65_JCS:
635             break;
636
637         case OP65_JEQ:
638             break;
639
640         case OP65_JMI:
641             break;
642
643         case OP65_JMP:
644             break;
645
646         case OP65_JNE:
647             break;
648
649         case OP65_JPL:
650             break;
651
652         case OP65_JSR:
653             /* Get the code info for the function */
654             GetFuncInfo (E->Arg, &Use, &Chg);
655             if (Chg & REG_A) {
656                 Out->RegA = -1;
657             }
658             if (Chg & REG_X) {
659                 Out->RegX = -1;
660             }
661             if (Chg & REG_Y) {
662                 Out->RegY = -1;
663             }
664             if (Chg & REG_TMP1) {
665                 Out->Tmp1 = -1;
666             }
667             if (Chg & REG_SREG_LO) {
668                 Out->SRegLo = -1;
669             }
670             if (Chg & REG_SREG_HI) {
671                 Out->SRegHi = -1;
672             }
673             /* Quick hack for some known functions: */
674             if (strcmp (E->Arg, "tosandax") == 0) {
675                 if (In->RegA == 0) {
676                     Out->RegA = 0;
677                 }
678                 if (In->RegX == 0) {
679                     Out->RegX = 0;
680                 }
681             } else if (strcmp (E->Arg, "tosorax") == 0) {
682                 if (In->RegA == 0xFF) {
683                     Out->RegA = 0xFF;
684                 }
685                 if (In->RegX == 0xFF) {
686                     Out->RegX = 0xFF;
687                 }
688             }
689             break;
690
691         case OP65_JVC:
692             break;
693
694         case OP65_JVS:
695             break;
696
697         case OP65_LDA:
698             if (CE_KnownImm (E)) {
699                 Out->RegA = (unsigned char) E->Num;
700             } else if (E->AM == AM65_ZP) {
701                 switch (GetKnownReg (E->Use, In)) {
702                     case REG_TMP1:
703                         Out->RegA = In->Tmp1;
704                         break;
705                     case REG_SREG_LO:
706                         Out->RegA = In->SRegLo;
707                         break;
708                     case REG_SREG_HI:
709                         Out->RegA = In->SRegHi;
710                         break;
711                     default:
712                         Out->RegA = -1;
713                         break;
714                 }
715             } else {
716                 /* A is now unknown */
717                 Out->RegA = -1;
718             }
719             break;
720
721         case OP65_LDX:
722             if (CE_KnownImm (E)) {
723                 Out->RegX = (unsigned char) E->Num;
724             } else if (E->AM == AM65_ZP) {
725                 switch (GetKnownReg (E->Use, In)) {
726                     case REG_TMP1:
727                         Out->RegX = In->Tmp1;
728                         break;
729                     case REG_SREG_LO:
730                         Out->RegX = In->SRegLo;
731                         break;
732                     case REG_SREG_HI:
733                         Out->RegX = In->SRegHi;
734                         break;
735                     default:
736                         Out->RegX = -1;
737                         break;
738                 }
739             } else {
740                 /* X is now unknown */
741                 Out->RegX = -1;
742             }
743             break;
744
745         case OP65_LDY:
746             if (CE_KnownImm (E)) {
747                 Out->RegY = (unsigned char) E->Num;
748             } else if (E->AM == AM65_ZP) {
749                 switch (GetKnownReg (E->Use, In)) {
750                     case REG_TMP1:
751                         Out->RegY = In->Tmp1;
752                         break;
753                     case REG_SREG_LO:
754                         Out->RegY = In->SRegLo;
755                         break;
756                     case REG_SREG_HI:
757                         Out->RegY = In->SRegHi;
758                         break;
759                     default:
760                         Out->RegY = -1;
761                         break;
762                 }
763             } else {
764                 /* Y is now unknown */
765                 Out->RegY = -1;
766             }
767             break;
768
769         case OP65_LSR:
770             if (E->AM == AM65_ACC && In->RegA >= 0) {
771                 Out->RegA = (In->RegA >> 1) & 0xFF;
772             } else if (E->AM == AM65_ZP) {
773                 switch (GetKnownReg (E->Chg, In)) {
774                     case REG_TMP1:
775                         Out->Tmp1 = (In->Tmp1 >> 1) & 0xFF;
776                         break;
777                     case REG_SREG_LO:
778                         Out->SRegLo = (In->SRegLo >> 1) & 0xFF;
779                         break;
780                     case REG_SREG_HI:
781                         Out->SRegHi = (In->SRegHi >> 1) & 0xFF;
782                         break;
783                 }
784             } else if (E->AM == AM65_ZPX) {
785                 /* Invalidates all ZP registers */
786                 RC_InvalidateZP (Out);
787             }
788             break;
789
790         case OP65_NOP:
791             break;
792
793         case OP65_ORA:
794             if (In->RegA >= 0) {
795                 if (CE_KnownImm (E)) {
796                     Out->RegA = In->RegA | (short) E->Num;
797                 } else if (E->AM == AM65_ZP) {
798                     switch (GetKnownReg (E->Use, In)) {
799                         case REG_TMP1:
800                             Out->RegA = In->RegA | In->Tmp1;
801                             break;
802                         case REG_SREG_LO:
803                             Out->RegA = In->RegA | In->SRegLo;
804                             break;
805                         case REG_SREG_HI:
806                             Out->RegA = In->RegA | In->SRegHi;
807                             break;
808                         default:
809                             Out->RegA = -1;
810                             break;
811                     }
812                 } else {
813                     /* A is now unknown */
814                     Out->RegA = -1;
815                 }
816             }
817             break;
818
819         case OP65_PHA:
820             break;
821
822         case OP65_PHP:
823             break;
824
825         case OP65_PHX:
826             break;
827
828         case OP65_PHY:
829             break;
830
831         case OP65_PLA:
832             Out->RegA = -1;
833             break;
834
835         case OP65_PLP:
836             break;
837
838         case OP65_PLX:
839             Out->RegX = -1;
840             break;
841
842         case OP65_PLY:
843             Out->RegY = -1;
844             break;
845
846         case OP65_ROL:
847             /* We don't know the value of the carry bit */
848             if (E->AM == AM65_ACC) {
849                 Out->RegA = -1;
850             } else if (E->AM == AM65_ZP) {
851                 switch (GetKnownReg (E->Chg, In)) {
852                     case REG_TMP1:
853                         Out->Tmp1 = -1;
854                         break;
855                     case REG_SREG_LO:
856                         Out->SRegLo = -1;
857                         break;
858                     case REG_SREG_HI:
859                         Out->SRegHi = -1;
860                         break;
861                 }
862             } else if (E->AM == AM65_ZPX) {
863                 /* Invalidates all ZP registers */
864                 RC_InvalidateZP (Out);
865             }
866             break;
867
868         case OP65_ROR:
869             /* We don't know the value of the carry bit */
870             if (E->AM == AM65_ACC) {
871                 Out->RegA = -1;
872             } else if (E->AM == AM65_ZP) {
873                 switch (GetKnownReg (E->Chg, In)) {
874                     case REG_TMP1:
875                         Out->Tmp1 = -1;
876                         break;
877                     case REG_SREG_LO:
878                         Out->SRegLo = -1;
879                         break;
880                     case REG_SREG_HI:
881                         Out->SRegHi = -1;
882                         break;
883                 }
884             } else if (E->AM == AM65_ZPX) {
885                 /* Invalidates all ZP registers */
886                 RC_InvalidateZP (Out);
887             }
888             break;
889
890         case OP65_RTI:
891             break;
892
893         case OP65_RTS:
894             break;
895
896         case OP65_SBC:
897             /* We don't know the value of the carry bit */
898             Out->RegA = -1;
899             break;
900
901         case OP65_SEC:
902             break;
903
904         case OP65_SED:
905             break;
906
907         case OP65_SEI:
908             break;
909
910         case OP65_STA:
911             if (E->AM == AM65_ZP) {
912                 switch (GetKnownReg (E->Chg, 0)) {
913                     case REG_TMP1:
914                         Out->Tmp1 = In->RegA;
915                         break;
916                     case REG_SREG_LO:
917                         Out->SRegLo = In->RegA;
918                         break;
919                     case REG_SREG_HI:
920                         Out->SRegHi = In->RegA;
921                         break;
922                 }
923             } else if (E->AM == AM65_ZPX) {
924                 /* Invalidates all ZP registers */
925                 RC_InvalidateZP (Out);
926             }
927             break;
928
929         case OP65_STX:
930             if (E->AM == AM65_ZP) {
931                 switch (GetKnownReg (E->Chg, 0)) {
932                     case REG_TMP1:
933                         Out->Tmp1 = In->RegX;
934                         break;
935                     case REG_SREG_LO:
936                         Out->SRegLo = In->RegX;
937                         break;
938                     case REG_SREG_HI:
939                         Out->SRegHi = In->RegX;
940                         break;
941                 }
942             } else if (E->AM == AM65_ZPX) {
943                 /* Invalidates all ZP registers */
944                 RC_InvalidateZP (Out);
945             }
946             break;
947
948         case OP65_STY:
949             if (E->AM == AM65_ZP) {
950                 switch (GetKnownReg (E->Chg, 0)) {
951                     case REG_TMP1:
952                         Out->Tmp1 = In->RegY;
953                         break;
954                     case REG_SREG_LO:
955                         Out->SRegLo = In->RegY;
956                         break;
957                     case REG_SREG_HI:
958                         Out->SRegHi = In->RegY;
959                         break;
960                 }
961             } else if (E->AM == AM65_ZPX) {
962                 /* Invalidates all ZP registers */
963                 RC_InvalidateZP (Out);
964             }
965             break;
966
967         case OP65_STZ:
968             if (E->AM == AM65_ZP) {
969                 switch (GetKnownReg (E->Chg, 0)) {
970                     case REG_TMP1:
971                         Out->Tmp1 = 0;
972                         break;
973                     case REG_SREG_LO:
974                         Out->SRegLo = 0;
975                         break;
976                     case REG_SREG_HI:
977                         Out->SRegHi = 0;
978                         break;
979                 }
980             } else if (E->AM == AM65_ZPX) {
981                 /* Invalidates all ZP registers */
982                 RC_InvalidateZP (Out);
983             }
984             break;
985
986         case OP65_TAX:
987             Out->RegX = In->RegA;
988             break;
989
990         case OP65_TAY:
991             Out->RegY = In->RegA;
992             break;
993
994         case OP65_TRB:
995             if (E->AM == AM65_ZPX) {
996                 /* Invalidates all ZP registers */
997                 RC_InvalidateZP (Out);
998             } else if (E->AM == AM65_ZP) {
999                 if (In->RegA >= 0) {
1000                     switch (GetKnownReg (E->Chg, In)) {
1001                         case REG_TMP1:
1002                             Out->Tmp1 &= ~In->RegA;
1003                             break;
1004                         case REG_SREG_LO:
1005                             Out->SRegLo &= ~In->RegA;
1006                             break;
1007                         case REG_SREG_HI:
1008                             Out->SRegHi &= ~In->RegA;
1009                             break;
1010                     }
1011                 } else {
1012                     switch (GetKnownReg (E->Chg, In)) {
1013                         case REG_TMP1:
1014                             Out->Tmp1 = -1;
1015                             break;
1016                         case REG_SREG_LO:
1017                             Out->SRegLo = -1;
1018                             break;
1019                         case REG_SREG_HI:
1020                             Out->SRegHi = -1;
1021                             break;
1022                     }
1023                 }
1024             }
1025             break;
1026
1027         case OP65_TSB:
1028             if (E->AM == AM65_ZPX) {
1029                 /* Invalidates all ZP registers */
1030                 RC_InvalidateZP (Out);
1031             } else if (E->AM == AM65_ZP) {
1032                 if (In->RegA >= 0) {
1033                     switch (GetKnownReg (E->Chg, In)) {
1034                         case REG_TMP1:
1035                             Out->Tmp1 |= In->RegA;
1036                             break;
1037                         case REG_SREG_LO:
1038                             Out->SRegLo |= In->RegA;
1039                             break;
1040                         case REG_SREG_HI:
1041                             Out->SRegHi |= In->RegA;
1042                             break;
1043                     }
1044                 } else {
1045                     switch (GetKnownReg (E->Chg, In)) {
1046                         case REG_TMP1:
1047                             Out->Tmp1 = -1;
1048                             break;
1049                         case REG_SREG_LO:
1050                             Out->SRegLo = -1;
1051                             break;
1052                         case REG_SREG_HI:
1053                             Out->SRegHi = -1;
1054                             break;
1055                     }
1056                 }
1057             }
1058             break;
1059
1060         case OP65_TSX:
1061             Out->RegX = -1;
1062             break;
1063
1064         case OP65_TXA:
1065             Out->RegA = In->RegX;
1066             break;
1067
1068         case OP65_TXS:
1069             break;
1070
1071         case OP65_TYA:
1072             Out->RegA = In->RegY;
1073             break;
1074
1075         default:
1076             break;
1077
1078     }
1079 }
1080
1081
1082
1083 static char* RegInfoDesc (unsigned U, char* Buf)
1084 /* Return a string containing register info */
1085 {
1086     Buf[0] = '\0';
1087
1088     strcat (Buf, U & REG_SREG_HI? "H" : "_");
1089     strcat (Buf, U & REG_SREG_LO? "L" : "_");
1090     strcat (Buf, U & REG_A?       "A" : "_");
1091     strcat (Buf, U & REG_X?       "X" : "_");
1092     strcat (Buf, U & REG_Y?       "Y" : "_");
1093     strcat (Buf, U & REG_TMP1?    "T1" : "__");
1094     strcat (Buf, U & REG_PTR1?    "1" : "_");
1095     strcat (Buf, U & REG_PTR2?    "2" : "_");
1096     strcat (Buf, U & REG_SAVE?    "V"  : "_");
1097
1098     return Buf;
1099 }
1100
1101
1102
1103 void CE_Output (const CodeEntry* E, FILE* F)
1104 /* Output the code entry to a file */
1105 {
1106     const OPCDesc* D;
1107     unsigned Chars;
1108     const char* Target;
1109
1110     /* If we have a label, print that */
1111     unsigned LabelCount = CollCount (&E->Labels);
1112     unsigned I;
1113     for (I = 0; I < LabelCount; ++I) {
1114         CL_Output (CollConstAt (&E->Labels, I), F);
1115     }
1116
1117     /* Get the opcode description */
1118     D = GetOPCDesc (E->OPC);
1119
1120     /* Print the mnemonic */
1121     Chars = fprintf (F, "\t%s", D->Mnemo);
1122
1123     /* Print the operand */
1124     switch (E->AM) {
1125
1126         case AM_IMP:
1127         case AM65_IMP:
1128             /* implicit */
1129             break;
1130
1131         case AM65_ACC:
1132             /* accumulator */
1133             Chars += fprintf (F, "%*sa", 9-Chars, "");
1134             break;
1135
1136         case AM_IMM:
1137         case AM65_IMM:
1138             /* immidiate */
1139             Chars += fprintf (F, "%*s#%s", 9-Chars, "", E->Arg);
1140             break;
1141
1142         case AM_ABS:
1143         case AM65_ZP:
1144         case AM65_ABS:
1145             /* zeropage and absolute */
1146             Chars += fprintf (F, "%*s%s", 9-Chars, "", E->Arg);
1147             break;
1148
1149         case AM65_ZPX:
1150         case AM65_ABSX:
1151             /* zeropage,X and absolute,X */
1152             Chars += fprintf (F, "%*s%s,x", 9-Chars, "", E->Arg);
1153             break;
1154
1155         case AM65_ABSY:
1156             /* absolute,Y */
1157             Chars += fprintf (F, "%*s%s,y", 9-Chars, "", E->Arg);
1158             break;
1159
1160         case AM65_ZPX_IND:
1161             /* (zeropage,x) */
1162             Chars += fprintf (F, "%*s(%s,x)", 9-Chars, "", E->Arg);
1163             break;
1164
1165         case AM65_ZP_INDY:
1166             /* (zeropage),y */
1167             Chars += fprintf (F, "%*s(%s),y", 9-Chars, "", E->Arg);
1168             break;
1169
1170         case AM65_ZP_IND:
1171             /* (zeropage) */
1172             Chars += fprintf (F, "%*s(%s)", 9-Chars, "", E->Arg);
1173             break;
1174
1175         case AM65_BRA:
1176             /* branch */
1177             Target = E->JumpTo? E->JumpTo->Name : E->Arg;
1178             Chars += fprintf (F, "%*s%s", 9-Chars, "", Target);
1179             break;
1180
1181         default:
1182             Internal ("Invalid addressing mode");
1183
1184     }
1185
1186     /* Print usage info if requested by the debugging flag */
1187     if (Debug) {
1188         char Use [128];
1189         char Chg [128];
1190         fprintf (F,
1191                  "%*s; USE: %-20s CHG: %-20s SIZE: %u\n",
1192                  30-Chars, "",
1193                  RegInfoDesc (E->Use, Use),
1194                  RegInfoDesc (E->Chg, Chg),
1195                  E->Size);
1196     } else {
1197         /* Terminate the line */
1198         fprintf (F, "\n");
1199     }
1200 }
1201
1202
1203
1204
1205
1206