1 /*****************************************************************************/
5 /* Opcode handler functions for the disassembler */
9 /* (C) 2000-2011, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
53 /*****************************************************************************/
54 /* Helper functions */
55 /*****************************************************************************/
59 static void Mnemonic (const char* M)
60 /* Indent and output a mnemonic */
68 static void OneLine (const OpcDesc* D, const char* Arg, ...) attribute ((format(printf, 2, 3)));
69 static void OneLine (const OpcDesc* D, const char* Arg, ...)
70 /* Output one line with the given mnemonic and argument */
80 xvsprintf (Buf, sizeof (Buf), Arg, ap);
85 /* Add the code stuff as comment */
86 LineComment (PC, D->Size);
94 static const char* GetAbsOverride (unsigned Flags, unsigned Addr)
95 /* If the instruction requires an abs override modifier, return the necessary
96 ** string, otherwise return the empty string.
99 if ((Flags & flAbsOverride) != 0 && Addr < 0x100) {
108 static const char* GetAddrArg (unsigned Flags, unsigned Addr)
109 /* Return an address argument - a label if we have one, or the address itself */
111 const char* Label = 0;
112 if (Flags & flUseLabel) {
113 Label = GetLabel (Addr, PC);
118 static char Buf [32];
120 xsprintf (Buf, sizeof (Buf), "$%02X", Addr);
122 xsprintf (Buf, sizeof (Buf), "$%04X", Addr);
130 static void GenerateLabel (unsigned Flags, unsigned Addr)
131 /* Generate a label in pass one if requested */
133 /* Generate labels in pass #1, and only if we don't have a label already */
134 if (Pass == 1 && !HaveLabel (Addr) &&
135 /* Check if we must create a label */
136 ((Flags & flGenLabel) != 0 ||
137 ((Flags & flUseLabel) != 0 && Addr >= CodeStart && Addr <= CodeEnd))) {
139 /* As a special case, handle ranges with tables or similar. Within
140 ** such a range with a granularity > 1, do only generate dependent
141 ** labels for all addresses but the first one. Be sure to generate
142 ** a label for the start of the range, however.
144 attr_t Style = GetStyleAttr (Addr);
145 unsigned Granularity = GetGranularity (Style);
147 if (Granularity == 1) {
148 /* Just add the label */
152 /* THIS CODE IS A MESS AND WILL FAIL ON SEVERAL CONDITIONS! ### */
155 /* Search for the start of the range or the last non dependent
156 ** label in the range.
160 unsigned LabelAddr = Addr;
161 while (LabelAddr > CodeStart) {
163 if (Style != GetStyleAttr (LabelAddr-1)) {
164 /* End of range reached */
168 LabelAttr = GetLabelAttr (LabelAddr);
169 if ((LabelAttr & (atIntLabel|atExtLabel)) != 0) {
170 /* The address has an internal or external label */
175 /* If the proposed label address doesn't have a label, define one */
176 if ((GetLabelAttr (LabelAddr) & (atIntLabel|atExtLabel)) == 0) {
177 AddIntLabel (LabelAddr);
180 /* Create the label */
181 Offs = Addr - LabelAddr;
185 AddDepLabel (Addr, atIntLabel, GetLabelName (LabelAddr), Offs);
193 /*****************************************************************************/
195 /*****************************************************************************/
199 void OH_Illegal (const OpcDesc* D attribute ((unused)))
206 void OH_Accumulator (const OpcDesc* D)
213 void OH_Implicit (const OpcDesc* D)
216 LineComment (PC, D->Size);
222 void OH_Immediate (const OpcDesc* D)
224 OneLine (D, "#$%02X", GetCodeByte (PC+1));
229 void OH_Direct (const OpcDesc* D)
231 /* Get the operand */
232 unsigned Addr = GetCodeByte (PC+1);
234 /* Generate a label in pass 1 */
235 GenerateLabel (D->Flags, Addr);
237 /* Output the line */
238 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
243 void OH_DirectX (const OpcDesc* D)
245 /* Get the operand */
246 unsigned Addr = GetCodeByte (PC+1);
248 /* Generate a label in pass 1 */
249 GenerateLabel (D->Flags, Addr);
251 /* Output the line */
252 OneLine (D, "%s,x", GetAddrArg (D->Flags, Addr));
257 void OH_DirectY (const OpcDesc* D)
259 /* Get the operand */
260 unsigned Addr = GetCodeByte (PC+1);
262 /* Generate a label in pass 1 */
263 GenerateLabel (D->Flags, Addr);
265 /* Output the line */
266 OneLine (D, "%s,y", GetAddrArg (D->Flags, Addr));
271 void OH_Absolute (const OpcDesc* D)
273 /* Get the operand */
274 unsigned Addr = GetCodeWord (PC+1);
276 /* Generate a label in pass 1 */
277 GenerateLabel (D->Flags, Addr);
279 /* Output the line */
280 OneLine (D, "%s%s", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
285 void OH_AbsoluteX (const OpcDesc* D)
287 /* Get the operand */
288 unsigned Addr = GetCodeWord (PC+1);
290 /* Generate a label in pass 1 */
291 GenerateLabel (D->Flags, Addr);
293 /* Output the line */
294 OneLine (D, "%s%s,x", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
299 void OH_AbsoluteY (const OpcDesc* D)
301 /* Get the operand */
302 unsigned Addr = GetCodeWord (PC+1);
304 /* Generate a label in pass 1 */
305 GenerateLabel (D->Flags, Addr);
307 /* Output the line */
308 OneLine (D, "%s%s,y", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
313 void OH_AbsoluteLong (const OpcDesc* D attribute ((unused)))
315 Error ("Not implemented");
320 void OH_AbsoluteLongX (const OpcDesc* D attribute ((unused)))
322 Error ("Not implemented");
327 void OH_Relative (const OpcDesc* D)
329 /* Get the operand */
330 signed char Offs = GetCodeByte (PC+1);
332 /* Calculate the target address */
333 unsigned Addr = (((int) PC+2) + Offs) & 0xFFFF;
335 /* Generate a label in pass 1 */
336 GenerateLabel (D->Flags, Addr);
338 /* Output the line */
339 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
344 void OH_RelativeLong (const OpcDesc* D attribute ((unused)))
346 Error ("Not implemented");
351 void OH_DirectIndirect (const OpcDesc* D)
353 /* Get the operand */
354 unsigned Addr = GetCodeByte (PC+1);
356 /* Generate a label in pass 1 */
357 GenerateLabel (D->Flags, Addr);
359 /* Output the line */
360 OneLine (D, "(%s)", GetAddrArg (D->Flags, Addr));
365 void OH_DirectIndirectY (const OpcDesc* D)
367 /* Get the operand */
368 unsigned Addr = GetCodeByte (PC+1);
370 /* Generate a label in pass 1 */
371 GenerateLabel (D->Flags, Addr);
373 /* Output the line */
374 OneLine (D, "(%s),y", GetAddrArg (D->Flags, Addr));
379 void OH_DirectXIndirect (const OpcDesc* D)
381 /* Get the operand */
382 unsigned Addr = GetCodeByte (PC+1);
384 /* Generate a label in pass 1 */
385 GenerateLabel (D->Flags, Addr);
387 /* Output the line */
388 OneLine (D, "(%s,x)", GetAddrArg (D->Flags, Addr));
393 void OH_AbsoluteIndirect (const OpcDesc* D)
395 /* Get the operand */
396 unsigned Addr = GetCodeWord (PC+1);
398 /* Generate a label in pass 1 */
399 GenerateLabel (D->Flags, Addr);
401 /* Output the line */
402 OneLine (D, "(%s)", GetAddrArg (D->Flags, Addr));
407 void OH_BitBranch (const OpcDesc* D)
409 /* Get the operands */
410 unsigned char TestAddr = GetCodeByte (PC+1);
411 signed char BranchOffs = GetCodeByte (PC+2);
413 /* Calculate the target address for the branch */
414 unsigned BranchAddr = (((int) PC+3) + BranchOffs) & 0xFFFF;
416 /* Generate labels in pass 1. The bit branch codes are special in that
417 ** they don't really match the remainder of the 6502 instruction set (they
418 ** are a Rockwell addon), so we must pass additional flags as direct
419 ** value to the second GenerateLabel call.
421 GenerateLabel (D->Flags, TestAddr);
422 GenerateLabel (flLabel, BranchAddr);
424 /* Output the line */
425 OneLine (D, "%s,%s", GetAddrArg (D->Flags, TestAddr), GetAddrArg (flLabel, BranchAddr));
430 void OH_ImmediateDirect (const OpcDesc* D)
432 /* Get the operand */
433 unsigned Addr = GetCodeByte (PC+2);
435 /* Generate a label in pass 1 */
436 GenerateLabel (D->Flags, Addr);
438 /* Output the line */
439 OneLine (D, "#$%02X,%s", GetCodeByte (PC+1), GetAddrArg (D->Flags, Addr));
444 void OH_ImmediateDirectX (const OpcDesc* D)
446 /* Get the operand */
447 unsigned Addr = GetCodeByte (PC+2);
449 /* Generate a label in pass 1 */
450 GenerateLabel (D->Flags, Addr);
452 /* Output the line */
453 OneLine (D, "#$%02X,%s,x", GetCodeByte (PC+1), GetAddrArg (D->Flags, Addr));
458 void OH_ImmediateAbsolute (const OpcDesc* D)
460 /* Get the operand */
461 unsigned Addr = GetCodeWord (PC+2);
463 /* Generate a label in pass 1 */
464 GenerateLabel (D->Flags, Addr);
466 /* Output the line */
467 OneLine (D, "#$%02X,%s%s", GetCodeByte (PC+1), GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
472 void OH_ImmediateAbsoluteX (const OpcDesc* D)
474 /* Get the operand */
475 unsigned Addr = GetCodeWord (PC+2);
477 /* Generate a label in pass 1 */
478 GenerateLabel (D->Flags, Addr);
480 /* Output the line */
481 OneLine (D, "#$%02X,%s%s,x", GetCodeByte (PC+1), GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
486 void OH_StackRelative (const OpcDesc* D attribute ((unused)))
488 Error ("Not implemented");
493 void OH_DirectIndirectLongX (const OpcDesc* D attribute ((unused)))
495 Error ("Not implemented");
500 void OH_StackRelativeIndirectY (const OpcDesc* D attribute ((unused)))
502 Error ("Not implemented");
507 void OH_DirectIndirectLong (const OpcDesc* D attribute ((unused)))
509 Error ("Not implemented");
514 void OH_DirectIndirectLongY (const OpcDesc* D attribute ((unused)))
516 Error ("Not implemented");
521 void OH_BlockMove (const OpcDesc* D attribute ((unused)))
523 /* Get source operand */
524 unsigned Src = GetCodeWord (PC+1);
525 /* Get destination operand */
526 unsigned Dst = GetCodeWord (PC+3);
528 /* Generate a label in pass 1 */
529 GenerateLabel (D->Flags, Src);
530 GenerateLabel (D->Flags, Dst);
532 /* Output the line */
533 OneLine (D, "%s%s,%s%s,#$%02X",
534 GetAbsOverride (D->Flags, Src), GetAddrArg (D->Flags, Src),
535 GetAbsOverride (D->Flags, Dst), GetAddrArg (D->Flags, Dst),
541 void OH_AbsoluteXIndirect (const OpcDesc* D attribute ((unused)))
543 /* Get the operand */
544 unsigned Addr = GetCodeWord (PC+1);
546 /* Generate a label in pass 1 */
547 GenerateLabel (D->Flags, Addr);
549 /* Output the line */
550 OneLine (D, "(%s,x)", GetAddrArg (D->Flags, Addr));
555 void OH_DirectImmediate (const OpcDesc* D)
557 /* Get the operand */
558 unsigned Addr = GetCodeByte (PC+1);
560 /* Generate a label in pass 1 */
561 GenerateLabel (D->Flags, Addr);
563 /* Output the line */
564 OneLine (D, "%s, #$%02X", GetAddrArg (D->Flags, Addr), GetCodeByte (PC+2));
569 void OH_ZeroPageBit (const OpcDesc* D)
571 unsigned Bit = GetCodeByte (PC) >> 5;
572 unsigned Addr = GetCodeByte (PC+1);
574 /* Generate a label in pass 1 */
575 GenerateLabel (D->Flags, Addr);
577 /* Output the line */
578 OneLine (D, "%01X,%s", Bit, GetAddrArg (D->Flags, Addr));
583 void OH_AccumulatorBit (const OpcDesc* D)
585 unsigned Bit = GetCodeByte (PC) >> 5;
587 /* Output the line */
588 OneLine (D, "%01X,a", Bit);
593 void OH_AccumulatorBitBranch (const OpcDesc* D)
595 unsigned Bit = GetCodeByte (PC) >> 5;
596 signed char BranchOffs = GetCodeByte (PC+1);
598 /* Calculate the target address for the branch */
599 unsigned BranchAddr = (((int) PC+3) + BranchOffs) & 0xFFFF;
601 /* Generate labels in pass 1 */
602 GenerateLabel (flLabel, BranchAddr);
604 /* Output the line */
605 OneLine (D, "%01X,a,%s", Bit, GetAddrArg (flLabel, BranchAddr));
610 void OH_JmpDirectIndirect (const OpcDesc* D)
612 OH_DirectIndirect (D);
613 if (NewlineAfterJMP) {
621 void OH_SpecialPage (const OpcDesc* D)
623 /* Get the operand */
624 unsigned Addr = 0xFF00 + GetCodeByte (PC+1);
626 /* Generate a label in pass 1 */
627 GenerateLabel (D->Flags, Addr);
629 /* OneLine (D, "$FF%02X", (CodeByte (PC+1)); */
630 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
635 void OH_Rts (const OpcDesc* D)
638 if (NewlineAfterRTS) {
646 void OH_JmpAbsolute (const OpcDesc* D)
649 if (NewlineAfterJMP) {
657 void OH_JmpAbsoluteIndirect (const OpcDesc* D)
659 OH_AbsoluteIndirect (D);
660 if (NewlineAfterJMP) {