]> git.sur5r.net Git - cc65/blob - src/cc65/codeent.c
00a93a947a6146c437b97bec709de7e31f138621
[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", (unsigned 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 int CE_UseLoadFlags (const CodeEntry* E)
380 /* Return true if the instruction uses any flags that are set by a load of
381  * a register (N and Z).
382  */
383 {
384     /* A branch will use the flags */
385     if (E->Info & OF_FBRA) {
386         return 1;
387     }
388
389     /* Call of a boolean transformer routine will also use the flags */
390     if (E->OPC == OP65_JSR) {
391         /* Get the condition that is evaluated and check it */
392         switch (FindBoolCmpCond (E->Arg)) {
393             case CMP_EQ:
394             case CMP_NE:
395             case CMP_GT:
396             case CMP_GE:
397             case CMP_LT:
398             case CMP_LE:
399             case CMP_UGT:
400             case CMP_ULE:
401             case CMP_INV:
402                 /* Will use the N or Z flags */
403                 return 1;
404
405
406             case CMP_UGE:       /* Uses only carry */
407             case CMP_ULT:       /* Dito */
408             default:            /* No bool transformer subroutine */
409                 return 0;
410         }
411     }
412
413     /* Anything else */
414     return 0;
415 }
416
417
418
419 void CE_FreeRegInfo (CodeEntry* E)
420 /* Free an existing register info struct */
421 {
422     if (E->RI) {
423         FreeRegInfo (E->RI);
424         E->RI = 0;
425     }
426 }
427
428
429
430 void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
431 /* Generate register info for this instruction. If an old info exists, it is
432  * overwritten.
433  */
434 {
435     /* Pointers to the register contents */
436     RegContents* In;
437     RegContents* Out;
438
439     /* Function register usage */
440     unsigned short Use, Chg;
441
442     /* If we don't have a register info struct, allocate one. */
443     if (E->RI == 0) {
444         E->RI = NewRegInfo (InputRegs);
445     } else {
446         if (InputRegs) {
447             E->RI->In  = *InputRegs;
448         } else {
449             RC_Invalidate (&E->RI->In);
450         }
451         E->RI->Out2 = E->RI->Out = E->RI->In;
452     }
453
454     /* Get pointers to the register contents */
455     In  = &E->RI->In;
456     Out = &E->RI->Out;
457
458     /* Handle the different instructions */
459     switch (E->OPC) {
460
461         case OP65_ADC:
462             /* We don't know the value of the carry, so the result is
463              * always unknown.
464              */
465             Out->RegA = -1;
466             break;
467
468         case OP65_AND:
469             if (In->RegA >= 0) {
470                 if (CE_KnownImm (E)) {
471                     Out->RegA = In->RegA & (short) E->Num;
472                 } else if (E->AM == AM65_ZP) {
473                     switch (GetKnownReg (E->Use, In)) {
474                         case REG_TMP1:
475                             Out->RegA = In->RegA & In->Tmp1;
476                             break;
477                         case REG_SREG_LO:
478                             Out->RegA = In->RegA & In->SRegLo;
479                             break;
480                         case REG_SREG_HI:
481                             Out->RegA = In->RegA & In->SRegHi;
482                             break;
483                         default:
484                             Out->RegA = -1;
485                             break;
486                     }
487                 } else {
488                     Out->RegA = -1;
489                 }
490             }
491             break;
492
493         case OP65_ASL:
494             if (E->AM == AM65_ACC && In->RegA >= 0) {
495                 Out->RegA = (In->RegA << 1) & 0xFF;
496             } else if (E->AM == AM65_ZP) {
497                 switch (GetKnownReg (E->Chg, In)) {
498                     case REG_TMP1:
499                         Out->Tmp1 = (In->Tmp1 << 1) & 0xFF;
500                         break;
501                     case REG_SREG_LO:
502                         Out->SRegLo = (In->SRegLo << 1) & 0xFF;
503                         break;
504                     case REG_SREG_HI:
505                         Out->SRegHi = (In->SRegHi << 1) & 0xFF;
506                         break;
507                 }
508             } else if (E->AM == AM65_ZPX) {
509                 /* Invalidates all ZP registers */
510                 RC_InvalidateZP (Out);
511             }
512             break;
513
514         case OP65_BCC:
515             break;
516
517         case OP65_BCS:
518             break;
519
520         case OP65_BEQ:
521             break;
522
523         case OP65_BIT:
524             break;
525
526         case OP65_BMI:
527             break;
528
529         case OP65_BNE:
530             break;
531
532         case OP65_BPL:
533             break;
534
535         case OP65_BRA:
536             break;
537
538         case OP65_BRK:
539             break;
540
541         case OP65_BVC:
542             break;
543
544         case OP65_BVS:
545             break;
546
547         case OP65_CLC:
548             break;
549
550         case OP65_CLD:
551             break;
552
553         case OP65_CLI:
554             break;
555
556         case OP65_CLV:
557             break;
558
559         case OP65_CMP:
560             break;
561
562         case OP65_CPX:
563             break;
564
565         case OP65_CPY:
566             break;
567
568         case OP65_DEA:
569             if (In->RegA >= 0) {
570                 Out->RegA = (In->RegA - 1) & 0xFF;
571             }
572             break;
573
574         case OP65_DEC:
575             if (E->AM == AM65_ACC && In->RegA >= 0) {
576                 Out->RegA = (In->RegA - 1) & 0xFF;
577             } else if (E->AM == AM65_ZP) {
578                 switch (GetKnownReg (E->Chg, In)) {
579                     case REG_TMP1:
580                         Out->Tmp1 = (In->Tmp1 - 1) & 0xFF;
581                         break;
582                     case REG_SREG_LO:
583                         Out->SRegLo = (In->SRegLo - 1) & 0xFF;
584                         break;
585                     case REG_SREG_HI:
586                         Out->SRegHi = (In->SRegHi - 1) & 0xFF;
587                         break;
588                 }
589             } else if (E->AM == AM65_ZPX) {
590                 /* Invalidates all ZP registers */
591                 RC_InvalidateZP (Out);
592             }
593             break;
594
595         case OP65_DEX:
596             if (In->RegX >= 0) {
597                 Out->RegX = (In->RegX - 1) & 0xFF;
598             }
599             break;
600
601         case OP65_DEY:
602             if (In->RegY >= 0) {
603                 Out->RegY = (In->RegY - 1) & 0xFF;
604             }
605             break;
606
607         case OP65_EOR:
608             if (In->RegA >= 0) {
609                 if (CE_KnownImm (E)) {
610                     Out->RegA = In->RegA ^ (short) E->Num;
611                 } else if (E->AM == AM65_ZP) {
612                     switch (GetKnownReg (E->Use, In)) {
613                         case REG_TMP1:
614                             Out->RegA = In->RegA ^ In->Tmp1;
615                             break;
616                         case REG_SREG_LO:
617                             Out->RegA = In->RegA ^ In->SRegLo;
618                             break;
619                         case REG_SREG_HI:
620                             Out->RegA = In->RegA ^ In->SRegHi;
621                             break;
622                         default:
623                             Out->RegA = -1;
624                             break;
625                     }
626                 } else {
627                     Out->RegA = -1;
628                 }
629             }
630             break;
631
632         case OP65_INA:
633             if (In->RegA >= 0) {
634                 Out->RegA = (In->RegA + 1) & 0xFF;
635             }
636             break;
637
638         case OP65_INC:
639             if (E->AM == AM65_ACC && In->RegA >= 0) {
640                 Out->RegA = (In->RegA + 1) & 0xFF;
641             } else if (E->AM == AM65_ZP) {
642                 switch (GetKnownReg (E->Chg, In)) {
643                     case REG_TMP1:
644                         Out->Tmp1 = (In->Tmp1 + 1) & 0xFF;
645                         break;
646                     case REG_SREG_LO:
647                         Out->SRegLo = (In->SRegLo + 1) & 0xFF;
648                         break;
649                     case REG_SREG_HI:
650                         Out->SRegHi = (In->SRegHi + 1) & 0xFF;
651                         break;
652                 }
653             } else if (E->AM == AM65_ZPX) {
654                 /* Invalidates all ZP registers */
655                 RC_InvalidateZP (Out);
656             }
657             break;
658
659         case OP65_INX:
660             if (In->RegX >= 0) {
661                 Out->RegX = (In->RegX + 1) & 0xFF;
662             }
663             break;
664
665         case OP65_INY:
666             if (In->RegY >= 0) {
667                 Out->RegY = (In->RegY + 1) & 0xFF;
668             }
669             break;
670
671         case OP65_JCC:
672             break;
673
674         case OP65_JCS:
675             break;
676
677         case OP65_JEQ:
678             break;
679
680         case OP65_JMI:
681             break;
682
683         case OP65_JMP:
684             break;
685
686         case OP65_JNE:
687             break;
688
689         case OP65_JPL:
690             break;
691
692         case OP65_JSR:
693             /* Get the code info for the function */
694             GetFuncInfo (E->Arg, &Use, &Chg);
695             if (Chg & REG_A) {
696                 Out->RegA = -1;
697             }
698             if (Chg & REG_X) {
699                 Out->RegX = -1;
700             }
701             if (Chg & REG_Y) {
702                 Out->RegY = -1;
703             }
704             if (Chg & REG_TMP1) {
705                 Out->Tmp1 = -1;
706             }
707             if (Chg & REG_SREG_LO) {
708                 Out->SRegLo = -1;
709             }
710             if (Chg & REG_SREG_HI) {
711                 Out->SRegHi = -1;
712             }
713             /* Quick hack for some known functions: */
714             if (strcmp (E->Arg, "tosandax") == 0) {
715                 if (In->RegA == 0) {
716                     Out->RegA = 0;
717                 }
718                 if (In->RegX == 0) {
719                     Out->RegX = 0;
720                 }
721             } else if (strcmp (E->Arg, "tosorax") == 0) {
722                 if (In->RegA == 0xFF) {
723                     Out->RegA = 0xFF;
724                 }
725                 if (In->RegX == 0xFF) {
726                     Out->RegX = 0xFF;
727                 }
728             }
729             break;
730
731         case OP65_JVC:
732             break;
733
734         case OP65_JVS:
735             break;
736
737         case OP65_LDA:
738             if (CE_KnownImm (E)) {
739                 Out->RegA = (unsigned char) E->Num;
740             } else if (E->AM == AM65_ZP) {
741                 switch (GetKnownReg (E->Use, In)) {
742                     case REG_TMP1:
743                         Out->RegA = In->Tmp1;
744                         break;
745                     case REG_SREG_LO:
746                         Out->RegA = In->SRegLo;
747                         break;
748                     case REG_SREG_HI:
749                         Out->RegA = In->SRegHi;
750                         break;
751                     default:
752                         Out->RegA = -1;
753                         break;
754                 }
755             } else {
756                 /* A is now unknown */
757                 Out->RegA = -1;
758             }
759             break;
760
761         case OP65_LDX:
762             if (CE_KnownImm (E)) {
763                 Out->RegX = (unsigned char) E->Num;
764             } else if (E->AM == AM65_ZP) {
765                 switch (GetKnownReg (E->Use, In)) {
766                     case REG_TMP1:
767                         Out->RegX = In->Tmp1;
768                         break;
769                     case REG_SREG_LO:
770                         Out->RegX = In->SRegLo;
771                         break;
772                     case REG_SREG_HI:
773                         Out->RegX = In->SRegHi;
774                         break;
775                     default:
776                         Out->RegX = -1;
777                         break;
778                 }
779             } else {
780                 /* X is now unknown */
781                 Out->RegX = -1;
782             }
783             break;
784
785         case OP65_LDY:
786             if (CE_KnownImm (E)) {
787                 Out->RegY = (unsigned char) E->Num;
788             } else if (E->AM == AM65_ZP) {
789                 switch (GetKnownReg (E->Use, In)) {
790                     case REG_TMP1:
791                         Out->RegY = In->Tmp1;
792                         break;
793                     case REG_SREG_LO:
794                         Out->RegY = In->SRegLo;
795                         break;
796                     case REG_SREG_HI:
797                         Out->RegY = In->SRegHi;
798                         break;
799                     default:
800                         Out->RegY = -1;
801                         break;
802                 }
803             } else {
804                 /* Y is now unknown */
805                 Out->RegY = -1;
806             }
807             break;
808
809         case OP65_LSR:
810             if (E->AM == AM65_ACC && In->RegA >= 0) {
811                 Out->RegA = (In->RegA >> 1) & 0xFF;
812             } else if (E->AM == AM65_ZP) {
813                 switch (GetKnownReg (E->Chg, In)) {
814                     case REG_TMP1:
815                         Out->Tmp1 = (In->Tmp1 >> 1) & 0xFF;
816                         break;
817                     case REG_SREG_LO:
818                         Out->SRegLo = (In->SRegLo >> 1) & 0xFF;
819                         break;
820                     case REG_SREG_HI:
821                         Out->SRegHi = (In->SRegHi >> 1) & 0xFF;
822                         break;
823                 }
824             } else if (E->AM == AM65_ZPX) {
825                 /* Invalidates all ZP registers */
826                 RC_InvalidateZP (Out);
827             }
828             break;
829
830         case OP65_NOP:
831             break;
832
833         case OP65_ORA:
834             if (In->RegA >= 0) {
835                 if (CE_KnownImm (E)) {
836                     Out->RegA = In->RegA | (short) E->Num;
837                 } else if (E->AM == AM65_ZP) {
838                     switch (GetKnownReg (E->Use, In)) {
839                         case REG_TMP1:
840                             Out->RegA = In->RegA | In->Tmp1;
841                             break;
842                         case REG_SREG_LO:
843                             Out->RegA = In->RegA | In->SRegLo;
844                             break;
845                         case REG_SREG_HI:
846                             Out->RegA = In->RegA | In->SRegHi;
847                             break;
848                         default:
849                             Out->RegA = -1;
850                             break;
851                     }
852                 } else {
853                     /* A is now unknown */
854                     Out->RegA = -1;
855                 }
856             }
857             break;
858
859         case OP65_PHA:
860             break;
861
862         case OP65_PHP:
863             break;
864
865         case OP65_PHX:
866             break;
867
868         case OP65_PHY:
869             break;
870
871         case OP65_PLA:
872             Out->RegA = -1;
873             break;
874
875         case OP65_PLP:
876             break;
877
878         case OP65_PLX:
879             Out->RegX = -1;
880             break;
881
882         case OP65_PLY:
883             Out->RegY = -1;
884             break;
885
886         case OP65_ROL:
887             /* We don't know the value of the carry bit */
888             if (E->AM == AM65_ACC) {
889                 Out->RegA = -1;
890             } else if (E->AM == AM65_ZP) {
891                 switch (GetKnownReg (E->Chg, In)) {
892                     case REG_TMP1:
893                         Out->Tmp1 = -1;
894                         break;
895                     case REG_SREG_LO:
896                         Out->SRegLo = -1;
897                         break;
898                     case REG_SREG_HI:
899                         Out->SRegHi = -1;
900                         break;
901                 }
902             } else if (E->AM == AM65_ZPX) {
903                 /* Invalidates all ZP registers */
904                 RC_InvalidateZP (Out);
905             }
906             break;
907
908         case OP65_ROR:
909             /* We don't know the value of the carry bit */
910             if (E->AM == AM65_ACC) {
911                 Out->RegA = -1;
912             } else if (E->AM == AM65_ZP) {
913                 switch (GetKnownReg (E->Chg, In)) {
914                     case REG_TMP1:
915                         Out->Tmp1 = -1;
916                         break;
917                     case REG_SREG_LO:
918                         Out->SRegLo = -1;
919                         break;
920                     case REG_SREG_HI:
921                         Out->SRegHi = -1;
922                         break;
923                 }
924             } else if (E->AM == AM65_ZPX) {
925                 /* Invalidates all ZP registers */
926                 RC_InvalidateZP (Out);
927             }
928             break;
929
930         case OP65_RTI:
931             break;
932
933         case OP65_RTS:
934             break;
935
936         case OP65_SBC:
937             /* We don't know the value of the carry bit */
938             Out->RegA = -1;
939             break;
940
941         case OP65_SEC:
942             break;
943
944         case OP65_SED:
945             break;
946
947         case OP65_SEI:
948             break;
949
950         case OP65_STA:
951             if (E->AM == AM65_ZP) {
952                 switch (GetKnownReg (E->Chg, 0)) {
953                     case REG_TMP1:
954                         Out->Tmp1 = In->RegA;
955                         break;
956                     case REG_SREG_LO:
957                         Out->SRegLo = In->RegA;
958                         break;
959                     case REG_SREG_HI:
960                         Out->SRegHi = In->RegA;
961                         break;
962                 }
963             } else if (E->AM == AM65_ZPX) {
964                 /* Invalidates all ZP registers */
965                 RC_InvalidateZP (Out);
966             }
967             break;
968
969         case OP65_STX:
970             if (E->AM == AM65_ZP) {
971                 switch (GetKnownReg (E->Chg, 0)) {
972                     case REG_TMP1:
973                         Out->Tmp1 = In->RegX;
974                         break;
975                     case REG_SREG_LO:
976                         Out->SRegLo = In->RegX;
977                         break;
978                     case REG_SREG_HI:
979                         Out->SRegHi = In->RegX;
980                         break;
981                 }
982             } else if (E->AM == AM65_ZPX) {
983                 /* Invalidates all ZP registers */
984                 RC_InvalidateZP (Out);
985             }
986             break;
987
988         case OP65_STY:
989             if (E->AM == AM65_ZP) {
990                 switch (GetKnownReg (E->Chg, 0)) {
991                     case REG_TMP1:
992                         Out->Tmp1 = In->RegY;
993                         break;
994                     case REG_SREG_LO:
995                         Out->SRegLo = In->RegY;
996                         break;
997                     case REG_SREG_HI:
998                         Out->SRegHi = In->RegY;
999                         break;
1000                 }
1001             } else if (E->AM == AM65_ZPX) {
1002                 /* Invalidates all ZP registers */
1003                 RC_InvalidateZP (Out);
1004             }
1005             break;
1006
1007         case OP65_STZ:
1008             if (E->AM == AM65_ZP) {
1009                 switch (GetKnownReg (E->Chg, 0)) {
1010                     case REG_TMP1:
1011                         Out->Tmp1 = 0;
1012                         break;
1013                     case REG_SREG_LO:
1014                         Out->SRegLo = 0;
1015                         break;
1016                     case REG_SREG_HI:
1017                         Out->SRegHi = 0;
1018                         break;
1019                 }
1020             } else if (E->AM == AM65_ZPX) {
1021                 /* Invalidates all ZP registers */
1022                 RC_InvalidateZP (Out);
1023             }
1024             break;
1025
1026         case OP65_TAX:
1027             Out->RegX = In->RegA;
1028             break;
1029
1030         case OP65_TAY:
1031             Out->RegY = In->RegA;
1032             break;
1033
1034         case OP65_TRB:
1035             if (E->AM == AM65_ZPX) {
1036                 /* Invalidates all ZP registers */
1037                 RC_InvalidateZP (Out);
1038             } else if (E->AM == AM65_ZP) {
1039                 if (In->RegA >= 0) {
1040                     switch (GetKnownReg (E->Chg, In)) {
1041                         case REG_TMP1:
1042                             Out->Tmp1 &= ~In->RegA;
1043                             break;
1044                         case REG_SREG_LO:
1045                             Out->SRegLo &= ~In->RegA;
1046                             break;
1047                         case REG_SREG_HI:
1048                             Out->SRegHi &= ~In->RegA;
1049                             break;
1050                     }
1051                 } else {
1052                     switch (GetKnownReg (E->Chg, In)) {
1053                         case REG_TMP1:
1054                             Out->Tmp1 = -1;
1055                             break;
1056                         case REG_SREG_LO:
1057                             Out->SRegLo = -1;
1058                             break;
1059                         case REG_SREG_HI:
1060                             Out->SRegHi = -1;
1061                             break;
1062                     }
1063                 }
1064             }
1065             break;
1066
1067         case OP65_TSB:
1068             if (E->AM == AM65_ZPX) {
1069                 /* Invalidates all ZP registers */
1070                 RC_InvalidateZP (Out);
1071             } else if (E->AM == AM65_ZP) {
1072                 if (In->RegA >= 0) {
1073                     switch (GetKnownReg (E->Chg, In)) {
1074                         case REG_TMP1:
1075                             Out->Tmp1 |= In->RegA;
1076                             break;
1077                         case REG_SREG_LO:
1078                             Out->SRegLo |= In->RegA;
1079                             break;
1080                         case REG_SREG_HI:
1081                             Out->SRegHi |= In->RegA;
1082                             break;
1083                     }
1084                 } else {
1085                     switch (GetKnownReg (E->Chg, In)) {
1086                         case REG_TMP1:
1087                             Out->Tmp1 = -1;
1088                             break;
1089                         case REG_SREG_LO:
1090                             Out->SRegLo = -1;
1091                             break;
1092                         case REG_SREG_HI:
1093                             Out->SRegHi = -1;
1094                             break;
1095                     }
1096                 }
1097             }
1098             break;
1099
1100         case OP65_TSX:
1101             Out->RegX = -1;
1102             break;
1103
1104         case OP65_TXA:
1105             Out->RegA = In->RegX;
1106             break;
1107
1108         case OP65_TXS:
1109             break;
1110
1111         case OP65_TYA:
1112             Out->RegA = In->RegY;
1113             break;
1114
1115         default:
1116             break;
1117
1118     }
1119 }
1120
1121
1122
1123 static char* RegInfoDesc (unsigned U, char* Buf)
1124 /* Return a string containing register info */
1125 {
1126     Buf[0] = '\0';
1127
1128     strcat (Buf, U & REG_SREG_HI? "H" : "_");
1129     strcat (Buf, U & REG_SREG_LO? "L" : "_");
1130     strcat (Buf, U & REG_A?       "A" : "_");
1131     strcat (Buf, U & REG_X?       "X" : "_");
1132     strcat (Buf, U & REG_Y?       "Y" : "_");
1133     strcat (Buf, U & REG_TMP1?    "T1" : "__");
1134     strcat (Buf, U & REG_PTR1?    "1" : "_");
1135     strcat (Buf, U & REG_PTR2?    "2" : "_");
1136     strcat (Buf, U & REG_SAVE?    "V"  : "_");
1137
1138     return Buf;
1139 }
1140
1141
1142
1143 void CE_Output (const CodeEntry* E, FILE* F)
1144 /* Output the code entry to a file */
1145 {
1146     const OPCDesc* D;
1147     unsigned Chars;
1148     const char* Target;
1149
1150     /* If we have a label, print that */
1151     unsigned LabelCount = CollCount (&E->Labels);
1152     unsigned I;
1153     for (I = 0; I < LabelCount; ++I) {
1154         CL_Output (CollConstAt (&E->Labels, I), F);
1155     }
1156
1157     /* Get the opcode description */
1158     D = GetOPCDesc (E->OPC);
1159
1160     /* Print the mnemonic */
1161     Chars = fprintf (F, "\t%s", D->Mnemo);
1162
1163     /* Print the operand */
1164     switch (E->AM) {
1165
1166         case AM_IMP:
1167         case AM65_IMP:
1168             /* implicit */
1169             break;
1170
1171         case AM65_ACC:
1172             /* accumulator */
1173             Chars += fprintf (F, "%*sa", 9-Chars, "");
1174             break;
1175
1176         case AM_IMM:
1177         case AM65_IMM:
1178             /* immidiate */
1179             Chars += fprintf (F, "%*s#%s", 9-Chars, "", E->Arg);
1180             break;
1181
1182         case AM_ABS:
1183         case AM65_ZP:
1184         case AM65_ABS:
1185             /* zeropage and absolute */
1186             Chars += fprintf (F, "%*s%s", 9-Chars, "", E->Arg);
1187             break;
1188
1189         case AM65_ZPX:
1190         case AM65_ABSX:
1191             /* zeropage,X and absolute,X */
1192             Chars += fprintf (F, "%*s%s,x", 9-Chars, "", E->Arg);
1193             break;
1194
1195         case AM65_ABSY:
1196             /* absolute,Y */
1197             Chars += fprintf (F, "%*s%s,y", 9-Chars, "", E->Arg);
1198             break;
1199
1200         case AM65_ZPX_IND:
1201             /* (zeropage,x) */
1202             Chars += fprintf (F, "%*s(%s,x)", 9-Chars, "", E->Arg);
1203             break;
1204
1205         case AM65_ZP_INDY:
1206             /* (zeropage),y */
1207             Chars += fprintf (F, "%*s(%s),y", 9-Chars, "", E->Arg);
1208             break;
1209
1210         case AM65_ZP_IND:
1211             /* (zeropage) */
1212             Chars += fprintf (F, "%*s(%s)", 9-Chars, "", E->Arg);
1213             break;
1214
1215         case AM65_BRA:
1216             /* branch */
1217             Target = E->JumpTo? E->JumpTo->Name : E->Arg;
1218             Chars += fprintf (F, "%*s%s", 9-Chars, "", Target);
1219             break;
1220
1221         default:
1222             Internal ("Invalid addressing mode");
1223
1224     }
1225
1226     /* Print usage info if requested by the debugging flag */
1227     if (Debug) {
1228         char Use [128];
1229         char Chg [128];
1230         fprintf (F,
1231                  "%*s; USE: %-20s CHG: %-20s SIZE: %u\n",
1232                  30-Chars, "",
1233                  RegInfoDesc (E->Use, Use),
1234                  RegInfoDesc (E->Chg, Chg),
1235                  E->Size);
1236     } else {
1237         /* Terminate the line */
1238         fprintf (F, "\n");
1239     }
1240 }
1241
1242
1243
1244
1245
1246