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