6 #define NOTUSEDERROR() do {werror(E_INTERNAL_ERROR, __FILE__, __LINE__, "error in notUsed()");} while(0)
8 // #define D(_s) { printf _s; fflush(stdout); }
11 #define ISINST(l, i) (!STRNCASECMP((l), (i), sizeof(i) - 1) && (!(l)[sizeof(i) - 1] || isspace((unsigned char)((l)[sizeof(i) - 1]))))
29 /*-----------------------------------------------------------------*/
30 /* incLabelJmpToCount - increment counter "jmpToCount" in entry */
31 /* of the list labelHash */
32 /*-----------------------------------------------------------------*/
34 incLabelJmpToCount (const char *label
)
36 labelHashEntry
*entry
;
38 entry
= getLabelRef (label
, _G
.head
);
45 /*-----------------------------------------------------------------*/
47 /* 1. extracts label in the opcode pl */
48 /* 2. increment "label jump-to count" in labelHash */
49 /* 3. search lineNode with label definition and return it */
50 /*-----------------------------------------------------------------*/
52 findLabel (const lineNode
*pl
)
57 /* 1. extract label in opcode */
59 /* In each jump the label is at the end */
60 p
= strlen (pl
->line
) - 1 + pl
->line
;
62 /* Skip trailing whitespace */
66 /* scan backward until space or ',' */
67 for (; p
> pl
->line
; p
--)
68 if (isspace(*p
) || *p
== ',')
78 /* skip ',' resp. '\t' */
81 /* 2. increment "label jump-to count" */
82 if (!incLabelJmpToCount (p
))
85 /* 3. search lineNode with label definition and return it */
86 for (cpl
= _G
.head
; cpl
; cpl
= cpl
->next
)
88 strncmp (p
, cpl
->line
, strlen(p
)) == 0 &&
89 cpl
->line
[strlen(p
)] == ':')
96 mos6502MightReadFlag(const lineNode
*pl
, const char *what
)
98 if (ISINST (pl
->line
, "adc") ||
99 ISINST (pl
->line
, "rol") ||
100 ISINST (pl
->line
, "ror") ||
101 ISINST (pl
->line
, "sbc"))
102 return (!strcmp(what
, "c"));
104 if (ISINST (pl
->line
, "bcc") || ISINST (pl
->line
, "bcs"))
105 return (!strcmp(what
, "c"));
107 if (ISINST (pl
->line
, "beq") || ISINST (pl
->line
, "bne"))
108 return (!strcmp(what
, "z"));
110 if (ISINST (pl
->line
, "bmi") || ISINST (pl
->line
, "bpl"))
111 return (!strcmp(what
, "n"));
113 if (ISINST (pl
->line
, "bvc") || ISINST (pl
->line
, "bvs"))
114 return (!strcmp(what
, "v"));
120 mos6502MightRead(const lineNode
*pl
, const char *what
)
122 if (!strcmp (what
, "n") || !strcmp (what
, "z") || !strcmp (what
, "c") || !strcmp (what
, "v"))
123 return (mos6502MightReadFlag (pl
, what
));
129 mos6502SurelyWritesFlag(const lineNode
*pl
, const char *what
)
131 if (ISINST (pl
->line
, "adc") ||
132 ISINST (pl
->line
, "sbc"))
133 return (!strcmp(what
, "n") || !strcmp(what
, "z") || !strcmp(what
, "c") || !strcmp(what
, "v"));
135 if (ISINST (pl
->line
, "asl") ||
136 ISINST (pl
->line
, "cmp") ||
137 ISINST (pl
->line
, "cpx") ||
138 ISINST (pl
->line
, "cpy") ||
139 ISINST (pl
->line
, "lsr") ||
140 ISINST (pl
->line
, "rol") ||
141 ISINST (pl
->line
, "ror"))
142 return (!strcmp(what
, "n") || !strcmp(what
, "z") || !strcmp(what
, "c"));
144 if (ISINST (pl
->line
, "and") ||
145 ISINST (pl
->line
, "dec") ||
146 ISINST (pl
->line
, "dex") ||
147 ISINST (pl
->line
, "dey") ||
148 ISINST (pl
->line
, "eor") ||
149 ISINST (pl
->line
, "inc") ||
150 ISINST (pl
->line
, "inx") ||
151 ISINST (pl
->line
, "iny") ||
152 ISINST (pl
->line
, "lda") ||
153 ISINST (pl
->line
, "ldx") ||
154 ISINST (pl
->line
, "ldy") ||
155 ISINST (pl
->line
, "ora") ||
156 ISINST (pl
->line
, "pla") ||
157 ISINST (pl
->line
, "tax") ||
158 ISINST (pl
->line
, "tay") ||
159 ISINST (pl
->line
, "tsx") ||
160 ISINST (pl
->line
, "tsa") ||
161 ISINST (pl
->line
, "tya"))
162 return (!strcmp(what
, "n") || !strcmp(what
, "z"));
164 if (ISINST (pl
->line
, "bit"))
165 return (!strcmp(what
, "n") || !strcmp(what
, "z") || !strcmp(what
, "v"));
167 if (ISINST (pl
->line
, "clc") ||
168 ISINST (pl
->line
, "sec"))
169 return (!strcmp(what
, "c"));
171 if (ISINST (pl
->line
, "clv"))
172 return (!strcmp(what
, "v"));
174 if (ISINST (pl
->line
, "plp") ||
175 ISINST (pl
->line
, "rti"))
182 mos6502SurelyWrites(const lineNode
*pl
, const char *what
)
184 if (!strcmp (what
, "n") || !strcmp (what
, "z") || !strcmp (what
, "c") || !strcmp (what
, "v"))
185 return (mos6502SurelyWritesFlag(pl
, what
));
192 mos6502UncondJump (const lineNode
*pl
)
194 return (ISINST (pl
->line
, "jmp"));
198 mos6502CondJump (const lineNode
*pl
)
200 return (ISINST (pl
->line
, "bpl") || ISINST (pl
->line
, "bmi") ||
201 ISINST (pl
->line
, "bvc") || ISINST (pl
->line
, "bvs") ||
202 ISINST (pl
->line
, "bcc") || ISINST (pl
->line
, "bcs") ||
203 ISINST (pl
->line
, "bne") || ISINST (pl
->line
, "beq"));
207 mos6502SurelyReturns (const lineNode
*pl
)
209 return (ISINST (pl
->line
, "rts") || ISINST (pl
->line
, "rti") );
212 /*-----------------------------------------------------------------*/
213 /* scan4op - "executes" and examines the assembler opcodes, */
214 /* follows conditional and un-conditional jumps. */
215 /* Moreover it registers all passed labels. */
219 /* scanning starts from pl; */
220 /* pl also returns the last scanned line */
221 /* const char *pReg */
222 /* points to a register (e.g. "ar0"). scan4op() tests for */
223 /* read or write operations with this register */
224 /* const char *untilOp */
225 /* points to NULL or a opcode (e.g. "push"). */
226 /* scan4op() returns if it hits this opcode. */
227 /* lineNode **plCond */
228 /* If a conditional branch is met plCond points to the */
229 /* lineNode of the conditional branch */
235 /* hit lineNode with "visited" flag set: scan4op() already */
236 /* scanned this opcode. */
237 /* S4O_FOUNDOPCODE */
238 /* found opcode and operand, to which untilOp and pReg are */
240 /* S4O_RD_OP, S4O_WR_OP */
241 /* hit an opcode reading or writing from pReg */
243 /* hit a conditional jump opcode. pl and plCond return the */
244 /* two possible branches. */
246 /* acall, lcall, ret and reti "terminate" a scan. */
247 /*-----------------------------------------------------------------*/
249 scan4op (lineNode
**pl
, const char *what
, const char *untilOp
,
252 for (; *pl
; *pl
= (*pl
)->next
)
254 if (!(*pl
)->line
|| (*pl
)->isDebug
|| (*pl
)->isComment
|| (*pl
)->isLabel
)
256 D(("Scanning %s for %s\n", (*pl
)->line
, what
));
257 /* don't optimize across inline assembler,
258 e.g. isLabel doesn't work there */
261 D(("S4O_ABORT at inline asm\n"));
267 D(("S4O_VISITED\n"));
271 (*pl
)->visited
= TRUE
;
273 if (mos6502MightRead (*pl
, what
))
279 // Check writes before conditional jumps, some jumps (btjf, btjt) write 'c'
280 if (mos6502SurelyWrites (*pl
, what
))
286 if (mos6502UncondJump (*pl
))
288 *pl
= findLabel (*pl
);
291 D(("S4O_ABORT at unconditional jump\n"));
295 if (mos6502CondJump (*pl
))
297 *plCond
= (*pl
)->next
->next
;
300 D(("S4O_ABORT at conditional jump\n"));
303 D(("S4O_CONDJMP\n"));
307 /* Don't need to check for de, hl since pdkMightRead() does that */
308 if (mos6502SurelyReturns (*pl
))
318 /*-----------------------------------------------------------------*/
319 /* doTermScan - scan through area 2. This small wrapper handles: */
320 /* - action required on different return values */
321 /* - recursion in case of conditional branches */
322 /*-----------------------------------------------------------------*/
324 doTermScan (lineNode
**pl
, const char *what
)
326 lineNode
*plConditional
;
327 for (;; *pl
= (*pl
)->next
)
329 switch (scan4op (pl
, what
, NULL
, &plConditional
))
334 /* all these are terminating conditions */
337 /* two possible destinations: recurse */
339 lineNode
*pl2
= plConditional
;
340 D(("CONDJMP trying other branch first\n"));
341 if (!doTermScan (&pl2
, what
))
343 D(("Other branch OK.\n"));
354 /*-----------------------------------------------------------------*/
355 /* univisitLines - clear "visited" flag in all lines */
356 /*-----------------------------------------------------------------*/
358 unvisitLines (lineNode
*pl
)
360 for (; pl
; pl
= pl
->next
)
364 bool mos6502notUsed (const char *what
, lineNode
*endPl
, lineNode
*head
)
370 unvisitLines (_G
.head
);
372 // Todo: Implement WDC 65C02 support, remove this check!
373 if (TARGET_IS_MOS65C02
)
377 return (doTermScan (&pl
, what
));
380 bool mos6502notUsedFrom (const char *what
, const char *label
, lineNode
*head
)
384 for (cpl
= head
; cpl
; cpl
= cpl
->next
)
385 if (cpl
->isLabel
&& !strncmp (label
, cpl
->line
, strlen(label
)))
386 return (mos6502notUsed (what
, cpl
, head
));