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