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