]> git.sur5r.net Git - cc65/blob - src/cc65/codeent.c
e6f9fe542949073ea7fc99f0b6ad69636d5f1398
[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
44 /* cc65 */
45 #include "codeinfo.h"
46 #include "error.h"
47 #include "global.h"
48 #include "codelab.h"
49 #include "opcodes.h"
50 #include "codeent.h"
51
52
53
54 /*****************************************************************************/
55 /*                                   Data                                    */
56 /*****************************************************************************/
57
58
59
60 /* Empty argument */
61 static char EmptyArg[] = "";
62
63
64
65 /*****************************************************************************/
66 /*                             Helper functions                              */
67 /*****************************************************************************/
68
69
70
71 static void FreeArg (char* Arg)
72 /* Free a code entry argument */
73 {
74     if (Arg != EmptyArg) {
75         xfree (Arg);
76     }
77 }
78
79
80
81 static char* GetArgCopy (const char* Arg)
82 /* Create an argument copy for assignment */
83 {
84     if (Arg && Arg[0] != '\0') {
85         /* Create a copy */
86         return xstrdup (Arg);
87     } else {
88         /* Use the empty argument string */
89         return EmptyArg;
90     }
91 }
92
93
94
95 static int NumArg (const char* Arg, unsigned long* Num)
96 /* If the given argument is numerical, convert it and return true. Otherwise
97  * set Num to zero and return false.
98  */
99 {
100     char* End;
101     unsigned long Val;
102
103     /* Determine the base */
104     int Base = 10;
105     if (*Arg == '$') {
106         ++Arg;
107         Base = 16;
108     } else if (*Arg == '%') {
109         ++Arg;
110         Base = 2;
111     }
112
113     /* Convert the value. strtol is not exactly what we want here, but it's
114      * cheap and may be replaced by something fancier later.
115      */
116     Val = strtoul (Arg, &End, Base);
117
118     /* Check if the conversion was successful */
119     if (*End != '\0') {
120
121         /* Could not convert */
122         *Num = 0;
123         return 0;
124
125     } else {
126
127         /* Conversion ok */
128         *Num = Val;
129         return 1;
130
131     }
132 }
133
134
135
136 static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D)
137 /* Set the Use and Chg in E */
138 {
139     /* If this is a subroutine call, or a jump to an external function,
140      * lookup the information about this function and use it. The jump itself
141      * does not change any registers, so we don't need to use the data from D.
142      */
143     if ((E->Info & (OF_BRA | OF_CALL)) != 0 && E->JumpTo == 0) {
144         /* A subroutine call or jump to external symbol (function exit) */
145         GetFuncInfo (E->Arg, &E->Use, &E->Chg);
146     } else {
147         /* Some other instruction. Use the values from the opcode description
148          * plus addressing mode info
149          */
150         E->Use = D->Use | GetAMUseInfo (E->AM);
151         E->Chg = D->Chg;
152     }
153 }
154
155
156
157 /*****************************************************************************/
158 /*                                   Code                                    */
159 /*****************************************************************************/
160
161
162
163 CodeEntry* NewCodeEntry (opc_t OPC, am_t AM, const char* Arg,
164                          CodeLabel* JumpTo, LineInfo* LI)
165 /* Create a new code entry, initialize and return it */
166 {
167     /* Get the opcode description */
168     const OPCDesc* D = GetOPCDesc (OPC);
169
170     /* Allocate memory */
171     CodeEntry* E = xmalloc (sizeof (CodeEntry));
172
173     /* Initialize the fields */
174     E->OPC    = D->OPC;
175     E->AM     = AM;
176     E->Arg    = GetArgCopy (Arg);
177     E->Flags  = NumArg (E->Arg, &E->Num)? CEF_NUMARG : 0;
178     E->Info   = D->Info;
179     E->Size   = GetInsnSize (E->OPC, E->AM);
180     E->JumpTo = JumpTo;
181     E->LI     = UseLineInfo (LI);
182     E->RI     = 0;
183     SetUseChgInfo (E, D);
184     InitCollection (&E->Labels);
185
186     /* If we have a label given, add this entry to the label */
187     if (JumpTo) {
188         CollAppend (&JumpTo->JumpFrom, E);
189     }
190
191     /* Return the initialized struct */
192     return E;
193 }
194
195
196
197 void FreeCodeEntry (CodeEntry* E)
198 /* Free the given code entry */
199 {
200     /* Free the string argument if we have one */
201     FreeArg (E->Arg);
202
203     /* Cleanup the collection */
204     DoneCollection (&E->Labels);
205
206     /* Release the line info */
207     ReleaseLineInfo (E->LI);
208
209     /* Delete the register info */
210     CE_FreeRegInfo (E);
211
212     /* Free the entry */
213     xfree (E);
214 }
215
216
217
218 void CE_ReplaceOPC (CodeEntry* E, opc_t OPC)
219 /* Replace the opcode of the instruction. This will also replace related info,
220  * Size, Use and Chg, but it will NOT update any arguments or labels.
221  */
222 {
223     /* Get the opcode descriptor */
224     const OPCDesc* D = GetOPCDesc (OPC);
225
226     /* Replace the opcode */
227     E->OPC  = OPC;
228     E->Info = D->Info;
229     E->Size = GetInsnSize (E->OPC, E->AM);
230     SetUseChgInfo (E, D);
231 }
232
233
234
235 int CodeEntriesAreEqual (const CodeEntry* E1, const CodeEntry* E2)
236 /* Check if both code entries are equal */
237 {
238     return E1->OPC == E2->OPC && E1->AM == E2->AM && strcmp (E1->Arg, E2->Arg) == 0;
239 }
240
241
242
243 void CE_AttachLabel (CodeEntry* E, CodeLabel* L)
244 /* Attach the label to the entry */
245 {
246     /* Add it to the entries label list */
247     CollAppend (&E->Labels, L);
248
249     /* Tell the label about it's owner */
250     L->Owner = E;
251 }
252
253
254
255 void CE_MoveLabel (CodeLabel* L, CodeEntry* E)
256 /* Move the code label L from it's former owner to the code entry E. */
257 {
258     /* Delete the label from the owner */
259     CollDeleteItem (&L->Owner->Labels, L);
260
261     /* Set the new owner */
262     CollAppend (&E->Labels, L);
263     L->Owner = E;
264 }
265
266
267
268 void CE_SetArg (CodeEntry* E, const char* Arg)
269 /* Set a new argument for the given code entry. An old string is deleted. */
270 {
271     /* Free the old argument */
272     FreeArg (E->Arg);
273
274     /* Assign the new one */
275     E->Arg = GetArgCopy (Arg);
276 }
277
278
279
280 int CE_KnownImm (const CodeEntry* E)
281 /* Return true if the argument of E is a known immediate value */
282 {
283     return (E->AM == AM65_IMM && (E->Flags & CEF_NUMARG) != 0);
284 }
285
286
287
288 void CE_FreeRegInfo (CodeEntry* E)
289 /* Free an existing register info struct */
290 {
291     if (E->RI) {
292         FreeRegInfo (E->RI);
293         E->RI = 0;
294     }
295 }
296
297
298
299 void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
300 /* Generate register info for this instruction. If an old info exists, it is
301  * overwritten.
302  */
303 {
304     /* Pointers to the register contents */
305     RegContents* In;
306     RegContents* Out;
307
308     /* Function register usage */
309     unsigned char Use, Chg;
310
311     /* If we don't have a register info struct, allocate one. */
312     if (E->RI == 0) {
313         E->RI = NewRegInfo (InputRegs);
314     } else {
315         if (InputRegs) {
316             E->RI->In  = *InputRegs;
317         } else {
318             RC_Invalidate (&E->RI->In);
319         }
320         E->RI->Out = E->RI->In;
321     }
322
323     /* Get pointers to the register contents */
324     In  = &E->RI->In;
325     Out = &E->RI->Out;
326
327     /* Handle the different instructions */
328     switch (E->OPC) {
329
330         case OP65_ADC:
331             /* We don't know the value of the carry, so the result is
332              * always unknown.
333              */
334             Out->RegA = -1;
335             break;
336
337         case OP65_AND:
338             if (In->RegA >= 0) {
339                 if (CE_KnownImm (E)) {
340                     Out->RegA = In->RegA & (short) E->Num;
341                 } else {
342                     Out->RegA = -1;
343                 }
344             }
345             break;
346
347         case OP65_ASL:
348             if (E->AM == AM65_ACC && In->RegA >= 0) {
349                 Out->RegA = (In->RegA << 1) & 0xFF;
350             }
351             break;
352
353         case OP65_BCC:
354             break;
355
356         case OP65_BCS:
357             break;
358
359         case OP65_BEQ:
360             break;
361
362         case OP65_BIT:
363             break;
364
365         case OP65_BMI:
366             break;
367
368         case OP65_BNE:
369             break;
370
371         case OP65_BPL:
372             break;
373
374         case OP65_BRA:
375             break;
376
377         case OP65_BRK:
378             break;
379
380         case OP65_BVC:
381             break;
382
383         case OP65_BVS:
384             break;
385
386         case OP65_CLC:
387             break;
388
389         case OP65_CLD:
390             break;
391
392         case OP65_CLI:
393             break;
394
395         case OP65_CLV:
396             break;
397
398         case OP65_CMP:
399             break;
400
401         case OP65_CPX:
402             break;
403
404         case OP65_CPY:
405             break;
406
407         case OP65_DEA:
408             if (In->RegA >= 0) {
409                 Out->RegA = In->RegA - 1;
410             }
411             break;
412
413         case OP65_DEC:
414             if (E->AM == AM65_ACC && In->RegA >= 0) {
415                 Out->RegA = In->RegA - 1;
416             }
417             break;
418
419         case OP65_DEX:
420             if (In->RegX >= 0) {
421                 Out->RegX = In->RegX - 1;
422             }
423             break;
424
425         case OP65_DEY:
426             if (In->RegY >= 0) {
427                 Out->RegY = In->RegY - 1;
428             }
429             break;
430
431         case OP65_EOR:
432             if (In->RegA >= 0) {
433                 if (CE_KnownImm (E)) {
434                     Out->RegA = In->RegA ^ (short) E->Num;
435                 } else {
436                     Out->RegA = -1;
437                 }
438             }
439             break;
440
441         case OP65_INA:
442             if (In->RegA >= 0) {
443                 Out->RegA = In->RegA + 1;
444             }
445             break;
446
447         case OP65_INC:
448             if (E->AM == AM65_ACC && In->RegA >= 0) {
449                 Out->RegA = In->RegA + 1;
450             }
451             break;
452
453         case OP65_INX:
454             if (In->RegX >= 0) {
455                 Out->RegX = In->RegX + 1;
456             }
457             break;
458
459         case OP65_INY:
460             if (In->RegY >= 0) {
461                 Out->RegY = In->RegY + 1;
462             }
463             break;
464
465         case OP65_JCC:
466             break;
467
468         case OP65_JCS:
469             break;
470
471         case OP65_JEQ:
472             break;
473
474         case OP65_JMI:
475             break;
476
477         case OP65_JMP:
478             break;
479
480         case OP65_JNE:
481             break;
482
483         case OP65_JPL:
484             break;
485
486         case OP65_JSR:
487             /* Get the code info for the function */
488             GetFuncInfo (E->Arg, &Use, &Chg);
489             if (Chg & REG_A) {
490                 Out->RegA = -1;
491             }
492             if (Chg & REG_X) {
493                 Out->RegX = -1;
494             }
495             if (Chg & REG_Y) {
496                 Out->RegY = -1;
497             }
498             break;
499
500         case OP65_JVC:
501             break;
502
503         case OP65_JVS:
504             break;
505
506         case OP65_LDA:
507             if (CE_KnownImm (E)) {
508                 Out->RegA = (unsigned char) E->Num;
509             } else {
510                 /* A is now unknown */
511                 Out->RegA = -1;
512             }
513             break;
514
515         case OP65_LDX:
516             if (CE_KnownImm (E)) {
517                 Out->RegX = (unsigned char) E->Num;
518             } else {
519                 /* X is now unknown */
520                 Out->RegX = -1;
521             }
522             break;
523
524         case OP65_LDY:
525             if (CE_KnownImm (E)) {
526                 Out->RegY = (unsigned char) E->Num;
527             } else {
528                 /* Y is now unknown */
529                 Out->RegY = -1;
530             }
531             break;
532
533         case OP65_LSR:
534             if (E->AM == AM65_ACC && In->RegA >= 0) {
535                 Out->RegA = (In->RegA >> 1) & 0xFF;
536             }
537             break;
538
539         case OP65_NOP:
540             break;
541
542         case OP65_ORA:
543             if (In->RegA >= 0) {
544                 if (CE_KnownImm (E)) {
545                     Out->RegA = In->RegA | (short) E->Num;
546                 } else {
547                     /* A is now unknown */
548                     Out->RegA = -1;
549                 }
550             }
551             break;
552
553         case OP65_PHA:
554             break;
555
556         case OP65_PHP:
557             break;
558
559         case OP65_PHX:
560             break;
561
562         case OP65_PHY:
563             break;
564
565         case OP65_PLA:
566             Out->RegA = -1;
567             break;
568
569         case OP65_PLP:
570             break;
571
572         case OP65_PLX:
573             Out->RegX = -1;
574             break;
575
576         case OP65_PLY:
577             Out->RegY = -1;
578             break;
579
580         case OP65_ROL:
581             Out->RegA = -1;
582             break;
583
584         case OP65_ROR:
585             Out->RegA = -1;
586             break;
587
588         case OP65_RTI:
589             break;
590
591         case OP65_RTS:
592             break;
593
594         case OP65_SBC:
595             /* We don't know the value of the carry bit */
596             Out->RegA = -1;
597             break;
598
599         case OP65_SEC:
600             break;
601
602         case OP65_SED:
603             break;
604
605         case OP65_SEI:
606             break;
607
608         case OP65_STA:
609             break;
610
611         case OP65_STX:
612             break;
613
614         case OP65_STY:
615             break;
616
617         case OP65_TAX:
618             Out->RegX = In->RegA;
619             break;
620
621         case OP65_TAY:
622             Out->RegY = In->RegA;
623             break;
624
625         case OP65_TRB:
626             /* For now... */
627             Out->RegA = -1;
628             break;
629
630         case OP65_TSB:
631             /* For now... */
632             Out->RegA = -1;
633             break;
634
635         case OP65_TSX:
636             Out->RegX = -1;
637             break;
638
639         case OP65_TXA:
640             Out->RegA = In->RegX;
641             break;
642
643         case OP65_TXS:
644             break;
645
646         case OP65_TYA:
647             Out->RegA = In->RegY;
648             break;
649
650         default:
651             break;
652
653     }
654 }
655
656
657
658 void CE_Output (const CodeEntry* E, FILE* F)
659 /* Output the code entry to a file */
660 {
661     const OPCDesc* D;
662     unsigned Chars;
663     const char* Target;
664
665     /* If we have a label, print that */
666     unsigned LabelCount = CollCount (&E->Labels);
667     unsigned I;
668     for (I = 0; I < LabelCount; ++I) {
669         CL_Output (CollConstAt (&E->Labels, I), F);
670     }
671
672     /* Get the opcode description */
673     D = GetOPCDesc (E->OPC);
674
675     /* Print the mnemonic */
676     Chars = fprintf (F, "\t%s", D->Mnemo);
677
678     /* Print the operand */
679     switch (E->AM) {
680
681         case AM_IMP:
682         case AM65_IMP:
683             /* implicit */
684             break;
685
686         case AM65_ACC:
687             /* accumulator */
688             Chars += fprintf (F, "%*sa", 9-Chars, "");
689             break;
690
691         case AM_IMM:
692         case AM65_IMM:
693             /* immidiate */
694             Chars += fprintf (F, "%*s#%s", 9-Chars, "", E->Arg);
695             break;
696
697         case AM_ABS:
698         case AM65_ZP:
699         case AM65_ABS:
700             /* zeropage and absolute */
701             Chars += fprintf (F, "%*s%s", 9-Chars, "", E->Arg);
702             break;
703
704         case AM65_ZPX:
705         case AM65_ABSX:
706             /* zeropage,X and absolute,X */
707             Chars += fprintf (F, "%*s%s,x", 9-Chars, "", E->Arg);
708             break;
709
710         case AM65_ABSY:
711             /* absolute,Y */
712             Chars += fprintf (F, "%*s%s,y", 9-Chars, "", E->Arg);
713             break;
714
715         case AM65_ZPX_IND:
716             /* (zeropage,x) */
717             Chars += fprintf (F, "%*s(%s,x)", 9-Chars, "", E->Arg);
718             break;
719
720         case AM65_ZP_INDY:
721             /* (zeropage),y */
722             Chars += fprintf (F, "%*s(%s),y", 9-Chars, "", E->Arg);
723             break;
724
725         case AM65_ZP_IND:
726             /* (zeropage) */
727             Chars += fprintf (F, "%*s(%s)", 9-Chars, "", E->Arg);
728             break;
729
730         case AM65_BRA:
731             /* branch */
732             Target = E->JumpTo? E->JumpTo->Name : E->Arg;
733             Chars += fprintf (F, "%*s%s", 9-Chars, "", Target);
734             break;
735
736         default:
737             Internal ("Invalid addressing mode");
738
739     }
740
741     /* Print usage info if requested by the debugging flag */
742     if (Debug) {
743         fprintf (F,
744                  "%*s; USE: %c%c%c CHG: %c%c%c SIZE: %u\n",
745                  30-Chars, "",
746                  (E->Use & REG_A)? 'A' : '_',
747                  (E->Use & REG_X)? 'X' : '_',
748                  (E->Use & REG_Y)? 'Y' : '_',
749                  (E->Chg & REG_A)? 'A' : '_',
750                  (E->Chg & REG_X)? 'X' : '_',
751                  (E->Chg & REG_Y)? 'Y' : '_',
752                  E->Size);
753     } else {
754         /* Terminate the line */
755         fprintf (F, "\n");
756     }
757 }
758
759
760
761
762
763