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