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