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