]> git.sur5r.net Git - cc65/blob - src/cc65/codeent.c
2a0c6164f30434fadad8ce9aff3e30b296c38110
[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 /*****************************************************************************/
137 /*                                   Code                                    */
138 /*****************************************************************************/
139
140
141
142 CodeEntry* NewCodeEntry (const OPCDesc* D, am_t AM, const char* Arg, CodeLabel* JumpTo)
143 /* Create a new code entry, initialize and return it */
144 {
145     /* Allocate memory */
146     CodeEntry* E = xmalloc (sizeof (CodeEntry));
147
148     /* Initialize the fields */
149     E->OPC      = D->OPC;
150     E->AM       = AM;
151     E->Size     = GetInsnSize (E->OPC, E->AM);
152     E->Hints    = 0;
153     E->Arg      = GetArgCopy (Arg);
154     if (NumArg (E->Arg, &E->Num)) {
155         E-> Flags = CEF_NUMARG;
156     } else {
157         E->Flags  = 0;
158     }
159     E->Info     = D->Info;
160     E->Use      = D->Use;
161     E->Chg      = D->Chg;
162     if (E->OPC == OPC_JSR) {
163         /* A subroutine call */
164         GetFuncInfo (E->Arg, &E->Use, &E->Chg);
165     } else {
166         /* Some other instruction */
167         E->Use |= GetAMUseInfo (E->AM);
168     }
169     E->JumpTo   = JumpTo;
170     InitCollection (&E->Labels);
171
172     /* If we have a label given, add this entry to the label */
173     if (JumpTo) {
174         CollAppend (&JumpTo->JumpFrom, E);
175     }
176
177     /* Return the initialized struct */
178     return E;
179 }
180
181
182
183 void FreeCodeEntry (CodeEntry* E)
184 /* Free the given code entry */
185 {
186     /* Free the string argument if we have one */
187     FreeArg (E->Arg);
188
189     /* Cleanup the collection */
190     DoneCollection (&E->Labels);
191
192     /* Free the entry */
193     xfree (E);
194 }
195
196
197
198 void ReplaceOPC (CodeEntry* E, opc_t OPC)
199 /* Replace the opcode of the instruction. This will also replace related info,
200  * Size, Use and Chg, but it will NOT update any arguments or labels.
201  */
202 {
203     /* Get the opcode descriptor */
204     const OPCDesc* D = GetOPCDesc (OPC);
205
206     /* Replace the opcode */
207     E->OPC      = OPC;
208     E->Size     = GetInsnSize (E->OPC, E->AM);
209     E->Info     = D->Info;
210     E->Use      = D->Use;
211     E->Chg      = D->Chg;
212     if (E->OPC == OPC_JSR) {
213         /* A subroutine call */
214         GetFuncInfo (E->Arg, &E->Use, &E->Chg);
215     } else {
216         /* Some other instruction */
217         E->Use |= GetAMUseInfo (E->AM);
218     }
219 }
220
221
222
223 int CodeEntriesAreEqual (const CodeEntry* E1, const CodeEntry* E2)
224 /* Check if both code entries are equal */
225 {
226     return E1->OPC == E2->OPC && E1->AM == E2->AM && strcmp (E1->Arg, E2->Arg) == 0;
227 }
228
229
230
231 void AttachCodeLabel (CodeEntry* E, CodeLabel* L)
232 /* Attach the label to the entry */
233 {
234     /* Mark the label as defined */
235     L->Flags |= LF_DEF;
236
237     /* Add it to the entries label list */
238     CollAppend (&E->Labels, L);
239
240     /* Tell the label about it's owner */
241     L->Owner = E;
242 }
243
244
245
246 int CodeEntryHasLabel (const CodeEntry* E)
247 /* Check if the given code entry has labels attached */
248 {
249     return (CollCount (&E->Labels) > 0);
250 }
251
252
253
254 unsigned GetCodeLabelCount (const CodeEntry* E)
255 /* Get the number of labels attached to this entry */
256 {
257     return CollCount (&E->Labels);
258 }
259
260
261
262 CodeLabel* GetCodeLabel (CodeEntry* E, unsigned Index)
263 /* Get a label from this code entry */
264 {
265     return CollAt (&E->Labels, Index);
266 }
267
268
269
270 void MoveCodeLabel (CodeLabel* L, CodeEntry* E)
271 /* Move the code label L from it's former owner to the code entry E. */
272 {
273     /* Delete the label from the owner */
274     CollDeleteItem (&L->Owner->Labels, L);
275
276     /* Set the new owner */
277     CollAppend (&E->Labels, L);
278     L->Owner = E;
279 }
280
281
282
283 int CodeEntryHasMark (const CodeEntry* E)
284 /* Return true if the given code entry has the CEF_USERMARK flag set */
285 {
286     return (E->Flags & CEF_USERMARK) != 0;
287 }
288
289
290
291 void CodeEntrySetMark (CodeEntry* E)
292 /* Set the CEF_USERMARK flag for the given entry */
293 {
294     E->Flags |= CEF_USERMARK;
295 }
296
297
298
299 void CodeEntryResetMark (CodeEntry* E)
300 /* Reset the CEF_USERMARK flag for the given entry */
301 {
302     E->Flags &= ~CEF_USERMARK;
303 }
304
305
306
307 void CodeEntrySetArg (CodeEntry* E, const char* Arg)
308 /* Set a new argument for the given code entry. An old string is deleted. */
309 {
310     /* Free the old argument */
311     FreeArg (E->Arg);
312
313     /* Assign the new one */
314     E->Arg = GetArgCopy (Arg);
315 }
316
317
318
319 void OutputCodeEntry (const CodeEntry* E, FILE* F)
320 /* Output the code entry to a file */
321 {
322     const OPCDesc* D;
323     unsigned Chars;
324     const char* Target;
325
326     /* If we have a label, print that */
327     unsigned LabelCount = CollCount (&E->Labels);
328     unsigned I;
329     for (I = 0; I < LabelCount; ++I) {
330         OutputCodeLabel (CollConstAt (&E->Labels, I), F);
331     }
332
333     /* Get the opcode description */
334     D = GetOPCDesc (E->OPC);
335
336     /* Print the mnemonic */
337     Chars = fprintf (F, "\t%s", D->Mnemo);
338
339     /* Print the operand */
340     switch (E->AM) {
341
342         case AM_IMP:
343             /* implicit */
344             break;
345
346         case AM_ACC:
347             /* accumulator */
348             Chars += fprintf (F, "%*sa", 9-Chars, "");
349             break;
350
351         case AM_IMM:
352             /* immidiate */
353             Chars += fprintf (F, "%*s#%s", 9-Chars, "", E->Arg);
354             break;
355
356         case AM_ZP:
357         case AM_ABS:
358             /* zeropage and absolute */
359             Chars += fprintf (F, "%*s%s", 9-Chars, "", E->Arg);
360             break;
361
362         case AM_ZPX:
363         case AM_ABSX:
364             /* zeropage,X and absolute,X */
365             Chars += fprintf (F, "%*s%s,x", 9-Chars, "", E->Arg);
366             break;
367
368         case AM_ABSY:
369             /* absolute,Y */
370             Chars += fprintf (F, "%*s%s,y", 9-Chars, "", E->Arg);
371             break;
372
373         case AM_ZPX_IND:
374             /* (zeropage,x) */
375             Chars += fprintf (F, "%*s(%s,x)", 9-Chars, "", E->Arg);
376             break;
377
378         case AM_ZP_INDY:
379             /* (zeropage),y */
380             Chars += fprintf (F, "%*s(%s),y", 9-Chars, "", E->Arg);
381             break;
382
383         case AM_ZP_IND:
384             /* (zeropage) */
385             Chars += fprintf (F, "%*s(%s)", 9-Chars, "", E->Arg);
386             break;
387
388         case AM_BRA:
389             /* branch */
390             Target = E->JumpTo? E->JumpTo->Name : E->Arg;
391             Chars += fprintf (F, "%*s%s", 9-Chars, "", Target);
392             break;
393
394         default:
395             Internal ("Invalid addressing mode");
396
397     }
398
399     /* Print usage info if requested by the debugging flag */
400 //    if (Debug) {
401         Chars += fprintf (F,
402                           "%*s; USE: %c%c%c CHG: %c%c%c",
403                           30-Chars, "",
404                           (E->Use & REG_A)? 'A' : '_',
405                           (E->Use & REG_X)? 'X' : '_',
406                           (E->Use & REG_Y)? 'Y' : '_',
407                           (E->Chg & REG_A)? 'A' : '_',
408                           (E->Chg & REG_X)? 'X' : '_',
409                           (E->Chg & REG_Y)? 'Y' : '_');
410 //    }
411
412     /* Terminate the line */
413     fprintf (F, "\n");
414 }
415
416
417
418