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