]> git.sur5r.net Git - cc65/blob - src/cc65/codeent.c
a891aeb3d1f863e3f6ede8ff5fd838e42c54f6dd
[cc65] / src / cc65 / codeent.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 codeent.c                                 */
4 /*                                                                           */
5 /*                            Code segment entry                             */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001-2004 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 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 <stdlib.h>
37 #include <string.h>
38
39 /* common */
40 #include "chartype.h"
41 #include "check.h"
42 #include "debugflag.h"
43 #include "xmalloc.h"
44 #include "xsprintf.h"
45
46 /* cc65 */
47 #include "codeinfo.h"
48 #include "error.h"
49 #include "global.h"
50 #include "codelab.h"
51 #include "opcodes.h"
52 #include "codeent.h"
53
54
55
56 /*****************************************************************************/
57 /*                                   Data                                    */
58 /*****************************************************************************/
59
60
61
62 /* Empty argument */
63 static char EmptyArg[] = "";
64
65
66
67 /*****************************************************************************/
68 /*                             Helper functions                              */
69 /*****************************************************************************/
70
71
72
73 static void FreeArg (char* Arg)
74 /* Free a code entry argument */
75 {
76     if (Arg != EmptyArg) {
77         xfree (Arg);
78     }
79 }
80
81
82
83 static char* GetArgCopy (const char* Arg)
84 /* Create an argument copy for assignment */
85 {
86     if (Arg && Arg[0] != '\0') {
87         /* Create a copy */
88         return xstrdup (Arg);
89     } else {
90         /* Use the empty argument string */
91         return EmptyArg;
92     }
93 }
94
95
96
97 static int NumArg (const char* Arg, unsigned long* Num)
98 /* If the given argument is numerical, convert it and return true. Otherwise
99  * set Num to zero and return false.
100  */
101 {
102     char* End;
103     unsigned long Val;
104
105     /* Determine the base */
106     int Base = 10;
107     if (*Arg == '$') {
108         ++Arg;
109         Base = 16;
110     } else if (*Arg == '%') {
111         ++Arg;
112         Base = 2;
113     }
114
115     /* Convert the value. strtol is not exactly what we want here, but it's
116      * cheap and may be replaced by something fancier later.
117      */
118     Val = strtoul (Arg, &End, Base);
119
120     /* Check if the conversion was successful */
121     if (*End != '\0') {
122
123         /* Could not convert */
124         *Num = 0;
125         return 0;
126
127     } else {
128
129         /* Conversion ok */
130         *Num = Val;
131         return 1;
132
133     }
134 }
135
136
137
138 static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D)
139 /* Set the Use and Chg in E */
140 {
141     const ZPInfo* Info;
142
143     /* If this is a subroutine call, or a jump to an external function,
144      * lookup the information about this function and use it. The jump itself
145      * does not change any registers, so we don't need to use the data from D.
146      */
147     if ((E->Info & (OF_BRA | OF_CALL)) != 0 && E->JumpTo == 0) {
148         /* A subroutine call or jump to external symbol (function exit) */
149         GetFuncInfo (E->Arg, &E->Use, &E->Chg);
150     } else {
151         /* Some other instruction. Use the values from the opcode description
152          * plus addressing mode info.
153          */
154         E->Use = D->Use | GetAMUseInfo (E->AM);
155         E->Chg = D->Chg;
156
157         /* Check for special zero page registers used */
158         switch (E->AM) {
159
160             case AM65_ACC:
161                 if (E->OPC == OP65_ASL || E->OPC == OP65_DEC ||
162                     E->OPC == OP65_INC || E->OPC == OP65_LSR ||
163                     E->OPC == OP65_ROL || E->OPC == OP65_ROR) {
164                     /* A is changed by these insns */
165                     E->Chg |= REG_A;
166                 }
167                 break;
168
169             case AM65_ZP:
170             case AM65_ABS:
171             /* Be conservative: */
172             case AM65_ZPX:
173             case AM65_ABSX:
174             case AM65_ABSY:
175                 Info = GetZPInfo (E->Arg);
176                 if (Info && Info->ByteUse != REG_NONE) {
177                     if (E->OPC == OP65_ASL || E->OPC == OP65_DEC ||
178                         E->OPC == OP65_INC || E->OPC == OP65_LSR ||
179                         E->OPC == OP65_ROL || E->OPC == OP65_ROR ||
180                         E->OPC == OP65_TRB || E->OPC == OP65_TSB) {
181                         /* The zp loc is both, input and output */
182                         E->Chg |= Info->ByteUse;
183                         E->Use |= Info->ByteUse;
184                     } else if ((E->Info & OF_STORE) != 0) {
185                         /* Just output */
186                         E->Chg |= Info->ByteUse;
187                     } else {
188                         /* Input only */
189                         E->Use |= Info->ByteUse;
190                     }
191                 }
192                 break;
193
194             case AM65_ZPX_IND:
195             case AM65_ZP_INDY:
196             case AM65_ZP_IND:
197                 Info = GetZPInfo (E->Arg);
198                 if (Info && Info->ByteUse != REG_NONE) {
199                     /* These addressing modes will never change the zp loc */
200                     E->Use |= Info->WordUse;
201                 }
202                 break;
203
204             default:
205                 /* Keep gcc silent */
206                 break;
207         }
208     }
209 }
210
211
212
213 /*****************************************************************************/
214 /*                                   Code                                    */
215 /*****************************************************************************/
216
217
218
219 const char* MakeHexArg (unsigned Num)
220 /* Convert Num into a string in the form $XY, suitable for passing it as an
221  * argument to NewCodeEntry, and return a pointer to the string.
222  * BEWARE: The function returns a pointer to a static buffer, so the value is
223  * gone if you call it twice (and apart from that it's not thread and signal
224  * safe).
225  */
226 {
227     static char Buf[16];
228     xsprintf (Buf, sizeof (Buf), "$%02X", (unsigned char) Num);
229     return Buf;
230 }
231
232
233
234 CodeEntry* NewCodeEntry (opc_t OPC, am_t AM, const char* Arg,
235                          CodeLabel* JumpTo, LineInfo* LI)
236 /* Create a new code entry, initialize and return it */
237 {
238     /* Get the opcode description */
239     const OPCDesc* D = GetOPCDesc (OPC);
240
241     /* Allocate memory */
242     CodeEntry* E = xmalloc (sizeof (CodeEntry));
243
244     /* Initialize the fields */
245     E->OPC    = D->OPC;
246     E->AM     = AM;
247     E->Size   = GetInsnSize (E->OPC, E->AM);
248     E->Arg    = GetArgCopy (Arg);
249     E->Flags  = NumArg (E->Arg, &E->Num)? CEF_NUMARG : 0;   /* Needs E->Arg */
250     E->Info   = D->Info;
251     E->JumpTo = JumpTo;
252     E->LI     = UseLineInfo (LI);
253     E->RI     = 0;
254     SetUseChgInfo (E, D);
255     InitCollection (&E->Labels);
256
257     /* If we have a label given, add this entry to the label */
258     if (JumpTo) {
259         CollAppend (&JumpTo->JumpFrom, E);
260     }
261
262     /* Return the initialized struct */
263     return E;
264 }
265
266
267
268 void FreeCodeEntry (CodeEntry* E)
269 /* Free the given code entry */
270 {
271     /* Free the string argument if we have one */
272     FreeArg (E->Arg);
273
274     /* Cleanup the collection */
275     DoneCollection (&E->Labels);
276
277     /* Release the line info */
278     ReleaseLineInfo (E->LI);
279
280     /* Delete the register info */
281     CE_FreeRegInfo (E);
282
283     /* Free the entry */
284     xfree (E);
285 }
286
287
288
289 void CE_ReplaceOPC (CodeEntry* E, opc_t OPC)
290 /* Replace the opcode of the instruction. This will also replace related info,
291  * Size, Use and Chg, but it will NOT update any arguments or labels.
292  */
293 {
294     /* Get the opcode descriptor */
295     const OPCDesc* D = GetOPCDesc (OPC);
296
297     /* Replace the opcode */
298     E->OPC  = OPC;
299     E->Info = D->Info;
300     E->Size = GetInsnSize (E->OPC, E->AM);
301     SetUseChgInfo (E, D);
302 }
303
304
305
306 int CodeEntriesAreEqual (const CodeEntry* E1, const CodeEntry* E2)
307 /* Check if both code entries are equal */
308 {
309     return E1->OPC == E2->OPC && E1->AM == E2->AM && strcmp (E1->Arg, E2->Arg) == 0;
310 }
311
312
313
314 void CE_AttachLabel (CodeEntry* E, CodeLabel* L)
315 /* Attach the label to the entry */
316 {
317     /* Add it to the entries label list */
318     CollAppend (&E->Labels, L);
319
320     /* Tell the label about it's owner */
321     L->Owner = E;
322 }
323
324
325
326 void CE_MoveLabel (CodeLabel* L, CodeEntry* E)
327 /* Move the code label L from it's former owner to the code entry E. */
328 {
329     /* Delete the label from the owner */
330     CollDeleteItem (&L->Owner->Labels, L);
331
332     /* Set the new owner */
333     CollAppend (&E->Labels, L);
334     L->Owner = E;
335 }
336
337
338
339 void CE_SetNumArg (CodeEntry* E, long Num)
340 /* Set a new numeric argument for the given code entry that must already
341  * have a numeric argument.
342  */
343 {
344     char Buf[16];
345
346     /* Check that the entry has a numerical argument */
347     CHECK (E->Flags & CEF_NUMARG);
348
349     /* Make the new argument string */
350     if (E->Size == 2) {
351         Num &= 0xFF;
352         xsprintf (Buf, sizeof (Buf), "$%02X", (unsigned) Num);
353     } else if (E->Size == 3) {
354         Num &= 0xFFFF;
355         xsprintf (Buf, sizeof (Buf), "$%04X", (unsigned) Num);
356     } else {
357         Internal ("Invalid instruction size in CE_SetNumArg");
358     }
359
360     /* Free the old argument */
361     FreeArg (E->Arg);
362
363     /* Assign the new one */
364     E->Arg = GetArgCopy (Buf);
365
366     /* Use the new numerical value */
367     E->Num = Num;
368 }
369
370
371
372 int CE_KnownImm (const CodeEntry* E)
373 /* Return true if the argument of E is a known immediate value */
374 {
375     return (E->AM == AM65_IMM && (E->Flags & CEF_NUMARG) != 0);
376 }
377
378
379
380 int CE_UseLoadFlags (const CodeEntry* E)
381 /* Return true if the instruction uses any flags that are set by a load of
382  * a register (N and Z).
383  */
384 {
385     /* A branch will use the flags */
386     if (E->Info & OF_FBRA) {
387         return 1;
388     }
389
390     /* Call of a boolean transformer routine will also use the flags */
391     if (E->OPC == OP65_JSR) {
392         /* Get the condition that is evaluated and check it */
393         switch (FindBoolCmpCond (E->Arg)) {
394             case CMP_EQ:
395             case CMP_NE:
396             case CMP_GT:
397             case CMP_GE:
398             case CMP_LT:
399             case CMP_LE:
400             case CMP_UGT:
401             case CMP_ULE:
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 = UNKNOWN_REGVAL;
466             break;
467
468         case OP65_AND:
469             if (RegValIsKnown (In->RegA)) {
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 & REG_ZP, In)) {
474                         case REG_TMP1:
475                             Out->RegA = In->RegA & In->Tmp1;
476                             break;
477                         case REG_PTR1_LO:
478                             Out->RegA = In->RegA & In->Ptr1Lo;
479                             break;
480                         case REG_PTR1_HI:
481                             Out->RegA = In->RegA & In->Ptr1Hi;
482                             break;
483                         case REG_SREG_LO:
484                             Out->RegA = In->RegA & In->SRegLo;
485                             break;
486                         case REG_SREG_HI:
487                             Out->RegA = In->RegA & In->SRegHi;
488                             break;
489                         default:
490                             Out->RegA = UNKNOWN_REGVAL;
491                             break;
492                     }
493                 } else {
494                     Out->RegA = UNKNOWN_REGVAL;
495                 }
496             }
497             break;
498
499         case OP65_ASL:
500             if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) {
501                 Out->RegA = (In->RegA << 1) & 0xFF;
502             } else if (E->AM == AM65_ZP) {
503                 switch (GetKnownReg (E->Chg & REG_ZP, In)) {
504                     case REG_TMP1:
505                         Out->Tmp1 = (In->Tmp1 << 1) & 0xFF;
506                         break;
507                     case REG_PTR1_LO:
508                         Out->Ptr1Lo = (In->Ptr1Lo << 1) & 0xFF;
509                         break;
510                     case REG_PTR1_HI:
511                         Out->Ptr1Hi = (In->Ptr1Hi << 1) & 0xFF;
512                         break;
513                     case REG_SREG_LO:
514                         Out->SRegLo = (In->SRegLo << 1) & 0xFF;
515                         break;
516                     case REG_SREG_HI:
517                         Out->SRegHi = (In->SRegHi << 1) & 0xFF;
518                         break;
519                 }
520             } else if (E->AM == AM65_ZPX) {
521                 /* Invalidates all ZP registers */
522                 RC_InvalidateZP (Out);
523             }
524             break;
525
526         case OP65_BCC:
527             break;
528
529         case OP65_BCS:
530             break;
531
532         case OP65_BEQ:
533             break;
534
535         case OP65_BIT:
536             break;
537
538         case OP65_BMI:
539             break;
540
541         case OP65_BNE:
542             break;
543
544         case OP65_BPL:
545             break;
546
547         case OP65_BRA:
548             break;
549
550         case OP65_BRK:
551             break;
552
553         case OP65_BVC:
554             break;
555
556         case OP65_BVS:
557             break;
558
559         case OP65_CLC:
560             break;
561
562         case OP65_CLD:
563             break;
564
565         case OP65_CLI:
566             break;
567
568         case OP65_CLV:
569             break;
570
571         case OP65_CMP:
572             break;
573
574         case OP65_CPX:
575             break;
576
577         case OP65_CPY:
578             break;
579
580         case OP65_DEA:
581             if (RegValIsKnown (In->RegA)) {
582                 Out->RegA = (In->RegA - 1) & 0xFF;
583             }
584             break;
585
586         case OP65_DEC:
587             if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) {
588                 Out->RegA = (In->RegA - 1) & 0xFF;
589             } else if (E->AM == AM65_ZP) {
590                 switch (GetKnownReg (E->Chg & REG_ZP, In)) {
591                     case REG_TMP1:
592                         Out->Tmp1 = (In->Tmp1 - 1) & 0xFF;
593                         break;
594                     case REG_PTR1_LO:
595                         Out->Ptr1Lo = (In->Ptr1Lo - 1) & 0xFF;
596                         break;
597                     case REG_PTR1_HI:
598                         Out->Ptr1Hi = (In->Ptr1Hi - 1) & 0xFF;
599                         break;
600                     case REG_SREG_LO:
601                         Out->SRegLo = (In->SRegLo - 1) & 0xFF;
602                         break;
603                     case REG_SREG_HI:
604                         Out->SRegHi = (In->SRegHi - 1) & 0xFF;
605                         break;
606                 }
607             } else if (E->AM == AM65_ZPX) {
608                 /* Invalidates all ZP registers */
609                 RC_InvalidateZP (Out);
610             }
611             break;
612
613         case OP65_DEX:
614             if (RegValIsKnown (In->RegX)) {
615                 Out->RegX = (In->RegX - 1) & 0xFF;
616             }
617             break;
618
619         case OP65_DEY:
620             if (RegValIsKnown (In->RegY)) {
621                 Out->RegY = (In->RegY - 1) & 0xFF;
622             }
623             break;
624
625         case OP65_EOR:
626             if (RegValIsKnown (In->RegA)) {
627                 if (CE_KnownImm (E)) {
628                     Out->RegA = In->RegA ^ (short) E->Num;
629                 } else if (E->AM == AM65_ZP) {
630                     switch (GetKnownReg (E->Use & REG_ZP, In)) {
631                         case REG_TMP1:
632                             Out->RegA = In->RegA ^ In->Tmp1;
633                             break;
634                         case REG_PTR1_LO:
635                             Out->RegA = In->RegA ^ In->Ptr1Lo;
636                             break;
637                         case REG_PTR1_HI:
638                             Out->RegA = In->RegA ^ In->Ptr1Hi;
639                             break;
640                         case REG_SREG_LO:
641                             Out->RegA = In->RegA ^ In->SRegLo;
642                             break;
643                         case REG_SREG_HI:
644                             Out->RegA = In->RegA ^ In->SRegHi;
645                             break;
646                         default:
647                             Out->RegA = UNKNOWN_REGVAL;
648                             break;
649                     }
650                 } else {
651                     Out->RegA = UNKNOWN_REGVAL;
652                 }
653             }
654             break;
655
656         case OP65_INA:
657             if (RegValIsKnown (In->RegA)) {
658                 Out->RegA = (In->RegA + 1) & 0xFF;
659             }
660             break;
661
662         case OP65_INC:
663             if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) {
664                 Out->RegA = (In->RegA + 1) & 0xFF;
665             } else if (E->AM == AM65_ZP) {
666                 switch (GetKnownReg (E->Chg & REG_ZP, In)) {
667                     case REG_TMP1:
668                         Out->Tmp1 = (In->Tmp1 + 1) & 0xFF;
669                         break;
670                     case REG_PTR1_LO:
671                         Out->Ptr1Lo = (In->Ptr1Lo + 1) & 0xFF;
672                         break;
673                     case REG_PTR1_HI:
674                         Out->Ptr1Hi = (In->Ptr1Hi + 1) & 0xFF;
675                         break;
676                     case REG_SREG_LO:
677                         Out->SRegLo = (In->SRegLo + 1) & 0xFF;
678                         break;
679                     case REG_SREG_HI:
680                         Out->SRegHi = (In->SRegHi + 1) & 0xFF;
681                         break;
682                 }
683             } else if (E->AM == AM65_ZPX) {
684                 /* Invalidates all ZP registers */
685                 RC_InvalidateZP (Out);
686             }
687             break;
688
689         case OP65_INX:
690             if (RegValIsKnown (In->RegX)) {
691                 Out->RegX = (In->RegX + 1) & 0xFF;
692             }
693             break;
694
695         case OP65_INY:
696             if (RegValIsKnown (In->RegY)) {
697                 Out->RegY = (In->RegY + 1) & 0xFF;
698             }
699             break;
700
701         case OP65_JCC:
702             break;
703
704         case OP65_JCS:
705             break;
706
707         case OP65_JEQ:
708             break;
709
710         case OP65_JMI:
711             break;
712
713         case OP65_JMP:
714             break;
715
716         case OP65_JNE:
717             break;
718
719         case OP65_JPL:
720             break;
721
722         case OP65_JSR:
723             /* Get the code info for the function */
724             GetFuncInfo (E->Arg, &Use, &Chg);
725             if (Chg & REG_A) {
726                 Out->RegA = UNKNOWN_REGVAL;
727             }
728             if (Chg & REG_X) {
729                 Out->RegX = UNKNOWN_REGVAL;
730             }
731             if (Chg & REG_Y) {
732                 Out->RegY = UNKNOWN_REGVAL;
733             }
734             if (Chg & REG_TMP1) {
735                 Out->Tmp1 = UNKNOWN_REGVAL;
736             }
737             if (Chg & REG_PTR1_LO) {
738                 Out->Ptr1Lo = UNKNOWN_REGVAL;
739             }
740             if (Chg & REG_PTR1_HI) {
741                 Out->Ptr1Hi = UNKNOWN_REGVAL;
742             }
743             if (Chg & REG_SREG_LO) {
744                 Out->SRegLo = UNKNOWN_REGVAL;
745             }
746             if (Chg & REG_SREG_HI) {
747                 Out->SRegHi = UNKNOWN_REGVAL;
748             }
749             /* ## FIXME: Quick hack for some known functions: */
750             if (strcmp (E->Arg, "tosandax") == 0) {
751                 if (In->RegA == 0) {
752                     Out->RegA = 0;
753                 }
754                 if (In->RegX == 0) {
755                     Out->RegX = 0;
756                 }
757             } else if (strcmp (E->Arg, "tosorax") == 0) {
758                 if (In->RegA == 0xFF) {
759                     Out->RegA = 0xFF;
760                 }
761                 if (In->RegX == 0xFF) {
762                     Out->RegX = 0xFF;
763                 }
764             } else if (FindBoolCmpCond (E->Arg) != CMP_INV) {
765                 Out->RegX = 0;
766             }
767             break;
768
769         case OP65_JVC:
770             break;
771
772         case OP65_JVS:
773             break;
774
775         case OP65_LDA:
776             if (CE_KnownImm (E)) {
777                 Out->RegA = (unsigned char) E->Num;
778             } else if (E->AM == AM65_ZP) {
779                 switch (GetKnownReg (E->Use & REG_ZP, In)) {
780                     case REG_TMP1:
781                         Out->RegA = In->Tmp1;
782                         break;
783                     case REG_PTR1_LO:
784                         Out->RegA = In->Ptr1Lo;
785                         break;
786                     case REG_PTR1_HI:
787                         Out->RegA = In->Ptr1Hi;
788                         break;
789                     case REG_SREG_LO:
790                         Out->RegA = In->SRegLo;
791                         break;
792                     case REG_SREG_HI:
793                         Out->RegA = In->SRegHi;
794                         break;
795                     default:
796                         Out->RegA = UNKNOWN_REGVAL;
797                         break;
798                 }
799             } else {
800                 /* A is now unknown */
801                 Out->RegA = UNKNOWN_REGVAL;
802             }
803             break;
804
805         case OP65_LDX:
806             if (CE_KnownImm (E)) {
807                 Out->RegX = (unsigned char) E->Num;
808             } else if (E->AM == AM65_ZP) {
809                 switch (GetKnownReg (E->Use & REG_ZP, In)) {
810                     case REG_TMP1:
811                         Out->RegX = In->Tmp1;
812                         break;
813                     case REG_PTR1_LO:
814                         Out->RegX = In->Ptr1Lo;
815                         break;
816                     case REG_PTR1_HI:
817                         Out->RegX = In->Ptr1Hi;
818                         break;
819                     case REG_SREG_LO:
820                         Out->RegX = In->SRegLo;
821                         break;
822                     case REG_SREG_HI:
823                         Out->RegX = In->SRegHi;
824                         break;
825                     default:
826                         Out->RegX = UNKNOWN_REGVAL;
827                         break;
828                 }
829             } else {
830                 /* X is now unknown */
831                 Out->RegX = UNKNOWN_REGVAL;
832             }
833             break;
834
835         case OP65_LDY:
836             if (CE_KnownImm (E)) {
837                 Out->RegY = (unsigned char) E->Num;
838             } else if (E->AM == AM65_ZP) {
839                 switch (GetKnownReg (E->Use & REG_ZP, In)) {
840                     case REG_TMP1:
841                         Out->RegY = In->Tmp1;
842                         break;
843                     case REG_PTR1_LO:
844                         Out->RegY = In->Ptr1Lo;
845                         break;
846                     case REG_PTR1_HI:
847                         Out->RegY = In->Ptr1Hi;
848                         break;
849                     case REG_SREG_LO:
850                         Out->RegY = In->SRegLo;
851                         break;
852                     case REG_SREG_HI:
853                         Out->RegY = In->SRegHi;
854                         break;
855                     default:
856                         Out->RegY = UNKNOWN_REGVAL;
857                         break;
858                 }
859             } else {
860                 /* Y is now unknown */
861                 Out->RegY = UNKNOWN_REGVAL;
862             }
863             break;
864
865         case OP65_LSR:
866             if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) {
867                 Out->RegA = (In->RegA >> 1) & 0xFF;
868             } else if (E->AM == AM65_ZP) {
869                 switch (GetKnownReg (E->Chg & REG_ZP, In)) {
870                     case REG_TMP1:
871                         Out->Tmp1 = (In->Tmp1 >> 1) & 0xFF;
872                         break;
873                     case REG_PTR1_LO:
874                         Out->Ptr1Lo = (In->Ptr1Lo >> 1) & 0xFF;
875                         break;
876                     case REG_PTR1_HI:
877                         Out->Ptr1Hi = (In->Ptr1Hi >> 1) & 0xFF;
878                         break;
879                     case REG_SREG_LO:
880                         Out->SRegLo = (In->SRegLo >> 1) & 0xFF;
881                         break;
882                     case REG_SREG_HI:
883                         Out->SRegHi = (In->SRegHi >> 1) & 0xFF;
884                         break;
885                 }
886             } else if (E->AM == AM65_ZPX) {
887                 /* Invalidates all ZP registers */
888                 RC_InvalidateZP (Out);
889             }
890             break;
891
892         case OP65_NOP:
893             break;
894
895         case OP65_ORA:
896             if (RegValIsKnown (In->RegA)) {
897                 if (CE_KnownImm (E)) {
898                     Out->RegA = In->RegA | (short) E->Num;
899                 } else if (E->AM == AM65_ZP) {
900                     switch (GetKnownReg (E->Use & REG_ZP, In)) {
901                         case REG_TMP1:
902                             Out->RegA = In->RegA | In->Tmp1;
903                             break;
904                         case REG_PTR1_LO:
905                             Out->RegA = In->RegA | In->Ptr1Lo;
906                             break;
907                         case REG_PTR1_HI:
908                             Out->RegA = In->RegA | In->Ptr1Hi;
909                             break;
910                         case REG_SREG_LO:
911                             Out->RegA = In->RegA | In->SRegLo;
912                             break;
913                         case REG_SREG_HI:
914                             Out->RegA = In->RegA | In->SRegHi;
915                             break;
916                         default:
917                             Out->RegA = UNKNOWN_REGVAL;
918                             break;
919                     }
920                 } else {
921                     /* A is now unknown */
922                     Out->RegA = UNKNOWN_REGVAL;
923                 }
924             }
925             break;
926
927         case OP65_PHA:
928             break;
929
930         case OP65_PHP:
931             break;
932
933         case OP65_PHX:
934             break;
935
936         case OP65_PHY:
937             break;
938
939         case OP65_PLA:
940             Out->RegA = UNKNOWN_REGVAL;
941             break;
942
943         case OP65_PLP:
944             break;
945
946         case OP65_PLX:
947             Out->RegX = UNKNOWN_REGVAL;
948             break;
949
950         case OP65_PLY:
951             Out->RegY = UNKNOWN_REGVAL;
952             break;
953
954         case OP65_ROL:
955             /* We don't know the value of the carry bit */
956             if (E->AM == AM65_ACC) {
957                 Out->RegA = UNKNOWN_REGVAL;
958             } else if (E->AM == AM65_ZP) {
959                 switch (GetKnownReg (E->Chg & REG_ZP, In)) {
960                     case REG_TMP1:
961                         Out->Tmp1 = UNKNOWN_REGVAL;
962                         break;
963                     case REG_PTR1_LO:
964                         Out->Ptr1Lo = UNKNOWN_REGVAL;
965                         break;
966                     case REG_PTR1_HI:
967                         Out->Ptr1Hi = UNKNOWN_REGVAL;
968                         break;
969                     case REG_SREG_LO:
970                         Out->SRegLo = UNKNOWN_REGVAL;
971                         break;
972                     case REG_SREG_HI:
973                         Out->SRegHi = UNKNOWN_REGVAL;
974                         break;
975                 }
976             } else if (E->AM == AM65_ZPX) {
977                 /* Invalidates all ZP registers */
978                 RC_InvalidateZP (Out);
979             }
980             break;
981
982         case OP65_ROR:
983             /* We don't know the value of the carry bit */
984             if (E->AM == AM65_ACC) {
985                 Out->RegA = UNKNOWN_REGVAL;
986             } else if (E->AM == AM65_ZP) {
987                 switch (GetKnownReg (E->Chg & REG_ZP, In)) {
988                     case REG_TMP1:
989                         Out->Tmp1 = UNKNOWN_REGVAL;
990                         break;
991                     case REG_PTR1_LO:
992                         Out->Ptr1Lo = UNKNOWN_REGVAL;
993                         break;
994                     case REG_PTR1_HI:
995                         Out->Ptr1Hi = UNKNOWN_REGVAL;
996                         break;
997                     case REG_SREG_LO:
998                         Out->SRegLo = UNKNOWN_REGVAL;
999                         break;
1000                     case REG_SREG_HI:
1001                         Out->SRegHi = UNKNOWN_REGVAL;
1002                         break;
1003                 }
1004             } else if (E->AM == AM65_ZPX) {
1005                 /* Invalidates all ZP registers */
1006                 RC_InvalidateZP (Out);
1007             }
1008             break;
1009
1010         case OP65_RTI:
1011             break;
1012
1013         case OP65_RTS:
1014             break;
1015
1016         case OP65_SBC:
1017             /* We don't know the value of the carry bit */
1018             Out->RegA = UNKNOWN_REGVAL;
1019             break;
1020
1021         case OP65_SEC:
1022             break;
1023
1024         case OP65_SED:
1025             break;
1026
1027         case OP65_SEI:
1028             break;
1029
1030         case OP65_STA:
1031             if (E->AM == AM65_ZP) {
1032                 switch (GetKnownReg (E->Chg & REG_ZP, 0)) {
1033                     case REG_TMP1:
1034                         Out->Tmp1 = In->RegA;
1035                         break;
1036                     case REG_PTR1_LO:
1037                         Out->Ptr1Lo = In->RegA;
1038                         break;
1039                     case REG_PTR1_HI:
1040                         Out->Ptr1Hi = In->RegA;
1041                         break;
1042                     case REG_SREG_LO:
1043                         Out->SRegLo = In->RegA;
1044                         break;
1045                     case REG_SREG_HI:
1046                         Out->SRegHi = In->RegA;
1047                         break;
1048                 }
1049             } else if (E->AM == AM65_ZPX) {
1050                 /* Invalidates all ZP registers */
1051                 RC_InvalidateZP (Out);
1052             }
1053             break;
1054
1055         case OP65_STX:
1056             if (E->AM == AM65_ZP) {
1057                 switch (GetKnownReg (E->Chg & REG_ZP, 0)) {
1058                     case REG_TMP1:
1059                         Out->Tmp1 = In->RegX;
1060                         break;
1061                     case REG_PTR1_LO:
1062                         Out->Ptr1Lo = In->RegX;
1063                         break;
1064                     case REG_PTR1_HI:
1065                         Out->Ptr1Hi = In->RegX;
1066                         break;
1067                     case REG_SREG_LO:
1068                         Out->SRegLo = In->RegX;
1069                         break;
1070                     case REG_SREG_HI:
1071                         Out->SRegHi = In->RegX;
1072                         break;
1073                 }
1074             } else if (E->AM == AM65_ZPX) {
1075                 /* Invalidates all ZP registers */
1076                 RC_InvalidateZP (Out);
1077             }
1078             break;
1079
1080         case OP65_STY:
1081             if (E->AM == AM65_ZP) {
1082                 switch (GetKnownReg (E->Chg & REG_ZP, 0)) {
1083                     case REG_TMP1:
1084                         Out->Tmp1 = In->RegY;
1085                         break;
1086                     case REG_PTR1_LO:
1087                         Out->Ptr1Lo = In->RegY;
1088                         break;
1089                     case REG_PTR1_HI:
1090                         Out->Ptr1Hi = In->RegY;
1091                         break;
1092                     case REG_SREG_LO:
1093                         Out->SRegLo = In->RegY;
1094                         break;
1095                     case REG_SREG_HI:
1096                         Out->SRegHi = In->RegY;
1097                         break;
1098                 }
1099             } else if (E->AM == AM65_ZPX) {
1100                 /* Invalidates all ZP registers */
1101                 RC_InvalidateZP (Out);
1102             }
1103             break;
1104
1105         case OP65_STZ:
1106             if (E->AM == AM65_ZP) {
1107                 switch (GetKnownReg (E->Chg & REG_ZP, 0)) {
1108                     case REG_TMP1:
1109                         Out->Tmp1 = 0;
1110                         break;
1111                     case REG_PTR1_LO:
1112                         Out->Ptr1Lo = 0;
1113                         break;
1114                     case REG_PTR1_HI:
1115                         Out->Ptr1Hi = 0;
1116                         break;
1117                     case REG_SREG_LO:
1118                         Out->SRegLo = 0;
1119                         break;
1120                     case REG_SREG_HI:
1121                         Out->SRegHi = 0;
1122                         break;
1123                 }
1124             } else if (E->AM == AM65_ZPX) {
1125                 /* Invalidates all ZP registers */
1126                 RC_InvalidateZP (Out);
1127             }
1128             break;
1129
1130         case OP65_TAX:
1131             Out->RegX = In->RegA;
1132             break;
1133
1134         case OP65_TAY:
1135             Out->RegY = In->RegA;
1136             break;
1137
1138         case OP65_TRB:
1139             if (E->AM == AM65_ZPX) {
1140                 /* Invalidates all ZP registers */
1141                 RC_InvalidateZP (Out);
1142             } else if (E->AM == AM65_ZP) {
1143                 if (RegValIsKnown (In->RegA)) {
1144                     switch (GetKnownReg (E->Chg & REG_ZP, In)) {
1145                         case REG_TMP1:
1146                             Out->Tmp1 &= ~In->RegA;
1147                             break;
1148                         case REG_PTR1_LO:
1149                             Out->Ptr1Lo &= ~In->RegA;
1150                             break;
1151                         case REG_PTR1_HI:
1152                             Out->Ptr1Hi &= ~In->RegA;
1153                             break;
1154                         case REG_SREG_LO:
1155                             Out->SRegLo &= ~In->RegA;
1156                             break;
1157                         case REG_SREG_HI:
1158                             Out->SRegHi &= ~In->RegA;
1159                             break;
1160                     }
1161                 } else {
1162                     switch (GetKnownReg (E->Chg & REG_ZP, In)) {
1163                         case REG_TMP1:
1164                             Out->Tmp1 = UNKNOWN_REGVAL;
1165                             break;
1166                         case REG_PTR1_LO:
1167                             Out->Ptr1Lo = UNKNOWN_REGVAL;
1168                             break;
1169                         case REG_PTR1_HI:
1170                             Out->Ptr1Hi = UNKNOWN_REGVAL;
1171                             break;
1172                         case REG_SREG_LO:
1173                             Out->SRegLo = UNKNOWN_REGVAL;
1174                             break;
1175                         case REG_SREG_HI:
1176                             Out->SRegHi = UNKNOWN_REGVAL;
1177                             break;
1178                     }
1179                 }
1180             }
1181             break;
1182
1183         case OP65_TSB:
1184             if (E->AM == AM65_ZPX) {
1185                 /* Invalidates all ZP registers */
1186                 RC_InvalidateZP (Out);
1187             } else if (E->AM == AM65_ZP) {
1188                 if (RegValIsKnown (In->RegA)) {
1189                     switch (GetKnownReg (E->Chg & REG_ZP, In)) {
1190                         case REG_TMP1:
1191                             Out->Tmp1 |= In->RegA;
1192                             break;
1193                         case REG_PTR1_LO:
1194                             Out->Ptr1Lo |= In->RegA;
1195                             break;
1196                         case REG_PTR1_HI:
1197                             Out->Ptr1Hi |= In->RegA;
1198                             break;
1199                         case REG_SREG_LO:
1200                             Out->SRegLo |= In->RegA;
1201                             break;
1202                         case REG_SREG_HI:
1203                             Out->SRegHi |= In->RegA;
1204                             break;
1205                     }
1206                 } else {
1207                     switch (GetKnownReg (E->Chg & REG_ZP, In)) {
1208                         case REG_TMP1:
1209                             Out->Tmp1 = UNKNOWN_REGVAL;
1210                             break;
1211                         case REG_PTR1_LO:
1212                             Out->Ptr1Lo = UNKNOWN_REGVAL;
1213                             break;
1214                         case REG_PTR1_HI:
1215                             Out->Ptr1Hi = UNKNOWN_REGVAL;
1216                             break;
1217                         case REG_SREG_LO:
1218                             Out->SRegLo = UNKNOWN_REGVAL;
1219                             break;
1220                         case REG_SREG_HI:
1221                             Out->SRegHi = UNKNOWN_REGVAL;
1222                             break;
1223                     }
1224                 }
1225             }
1226             break;
1227
1228         case OP65_TSX:
1229             Out->RegX = UNKNOWN_REGVAL;
1230             break;
1231
1232         case OP65_TXA:
1233             Out->RegA = In->RegX;
1234             break;
1235
1236         case OP65_TXS:
1237             break;
1238
1239         case OP65_TYA:
1240             Out->RegA = In->RegY;
1241             break;
1242
1243         default:
1244             break;
1245
1246     }
1247 }
1248
1249
1250
1251 static char* RegInfoDesc (unsigned U, char* Buf)
1252 /* Return a string containing register info */
1253 {
1254     Buf[0] = '\0';
1255
1256     strcat (Buf, U & REG_SREG_HI? "H" : "_");
1257     strcat (Buf, U & REG_SREG_LO? "L" : "_");
1258     strcat (Buf, U & REG_A?       "A" : "_");
1259     strcat (Buf, U & REG_X?       "X" : "_");
1260     strcat (Buf, U & REG_Y?       "Y" : "_");
1261     strcat (Buf, U & REG_TMP1?    "T1" : "__");
1262     strcat (Buf, U & REG_PTR1?    "1" : "_");
1263     strcat (Buf, U & REG_PTR2?    "2" : "_");
1264     strcat (Buf, U & REG_SAVE?    "V"  : "_");
1265     strcat (Buf, U & REG_SP?      "S" : "_");
1266
1267     return Buf;
1268 }
1269
1270
1271
1272 static char* RegContentDesc (const RegContents* RC, char* Buf)
1273 /* Return a string containing register contents */
1274 {
1275     char* B = Buf;
1276
1277     if (RegValIsUnknown (RC->RegA)) {
1278         strcpy (B, "A:XX ");
1279     } else {
1280         sprintf (B, "A:%02X ", RC->RegA);
1281     }
1282     B += 5;
1283     if (RegValIsUnknown (RC->RegX)) {
1284         strcpy (B, "X:XX ");
1285     } else {
1286         sprintf (B, "X:%02X ", RC->RegX);
1287     }
1288     B += 5;
1289     if (RegValIsUnknown (RC->RegY)) {
1290         strcpy (B, "Y:XX");
1291     } else {
1292         sprintf (B, "Y:%02X", RC->RegY);
1293     }
1294     B += 4;
1295
1296     return Buf;
1297 }
1298
1299
1300
1301 void CE_Output (const CodeEntry* E, FILE* F)
1302 /* Output the code entry to a file */
1303 {
1304     const OPCDesc* D;
1305     unsigned Chars;
1306     const char* Target;
1307
1308     /* If we have a label, print that */
1309     unsigned LabelCount = CollCount (&E->Labels);
1310     unsigned I;
1311     for (I = 0; I < LabelCount; ++I) {
1312         CL_Output (CollConstAt (&E->Labels, I), F);
1313     }
1314
1315     /* Get the opcode description */
1316     D = GetOPCDesc (E->OPC);
1317
1318     /* Print the mnemonic */
1319     Chars = fprintf (F, "\t%s", D->Mnemo);
1320
1321     /* Print the operand */
1322     switch (E->AM) {
1323
1324         case AM_IMP:
1325         case AM65_IMP:
1326             /* implicit */
1327             break;
1328
1329         case AM65_ACC:
1330             /* accumulator */
1331             Chars += fprintf (F, "%*sa", 9-Chars, "");
1332             break;
1333
1334         case AM_IMM:
1335         case AM65_IMM:
1336             /* immidiate */
1337             Chars += fprintf (F, "%*s#%s", 9-Chars, "", E->Arg);
1338             break;
1339
1340         case AM_ABS:
1341         case AM65_ZP:
1342         case AM65_ABS:
1343             /* zeropage and absolute */
1344             Chars += fprintf (F, "%*s%s", 9-Chars, "", E->Arg);
1345             break;
1346
1347         case AM65_ZPX:
1348         case AM65_ABSX:
1349             /* zeropage,X and absolute,X */
1350             Chars += fprintf (F, "%*s%s,x", 9-Chars, "", E->Arg);
1351             break;
1352
1353         case AM65_ABSY:
1354             /* absolute,Y */
1355             Chars += fprintf (F, "%*s%s,y", 9-Chars, "", E->Arg);
1356             break;
1357
1358         case AM65_ZPX_IND:
1359             /* (zeropage,x) */
1360             Chars += fprintf (F, "%*s(%s,x)", 9-Chars, "", E->Arg);
1361             break;
1362
1363         case AM65_ZP_INDY:
1364             /* (zeropage),y */
1365             Chars += fprintf (F, "%*s(%s),y", 9-Chars, "", E->Arg);
1366             break;
1367
1368         case AM65_ZP_IND:
1369             /* (zeropage) */
1370             Chars += fprintf (F, "%*s(%s)", 9-Chars, "", E->Arg);
1371             break;
1372
1373         case AM65_BRA:
1374             /* branch */
1375             Target = E->JumpTo? E->JumpTo->Name : E->Arg;
1376             Chars += fprintf (F, "%*s%s", 9-Chars, "", Target);
1377             break;
1378
1379         default:
1380             Internal ("Invalid addressing mode");
1381
1382     }
1383
1384     /* Print usage info if requested by the debugging flag */
1385     if (Debug) {
1386         char Use [128];
1387         char Chg [128];
1388         fprintf (F,
1389                  "%*s; USE: %-12s CHG: %-12s SIZE: %u",
1390                  30-Chars, "",
1391                  RegInfoDesc (E->Use, Use),
1392                  RegInfoDesc (E->Chg, Chg),
1393                  E->Size);
1394
1395         if (E->RI) {
1396             char RegIn[32];
1397             char RegOut[32];
1398             fprintf (F,
1399                      "    In %s  Out %s",
1400                      RegContentDesc (&E->RI->In, RegIn),
1401                      RegContentDesc (&E->RI->Out, RegOut));
1402         }
1403     }
1404
1405     /* Terminate the line */
1406     fprintf (F, "\n");
1407 }
1408
1409
1410
1411
1412
1413