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 /*****************************************************************************/
54 /*****************************************************************************/
55 /* Helper functions */
56 /*****************************************************************************/
60 static void Mnemonic (const char* M)
61 /* Indent and output a mnemonic */
69 static void OneLine (const OpcDesc* D, const char* Arg, ...) attribute ((format(printf, 2, 3)));
70 static void OneLine (const OpcDesc* D, const char* Arg, ...)
71 /* Output one line with the given mnemonic and argument */
81 xvsprintf (Buf, sizeof (Buf), Arg, ap);
86 /* Add the code stuff as comment */
87 LineComment (PC, D->Size);
95 static const char* GetAbsOverride (unsigned Flags, unsigned Addr)
96 /* If the instruction requires an abs override modifier, return the necessary
97 ** string, otherwise return the empty string.
100 if ((Flags & flAbsOverride) != 0 && Addr < 0x100) {
109 static const char* GetAddrArg (unsigned Flags, unsigned Addr)
110 /* Return an address argument - a label if we have one, or the address itself */
112 const char* Label = 0;
113 if (Flags & flUseLabel) {
114 Label = GetLabel (Addr, PC);
119 static char Buf [32];
121 xsprintf (Buf, sizeof (Buf), "$%02X", Addr);
123 xsprintf (Buf, sizeof (Buf), "$%04X", Addr);
131 static void GenerateLabel (unsigned Flags, unsigned Addr)
132 /* Generate a label in pass one if requested */
134 /* Generate labels in pass #1, and only if we don't have a label already */
135 if (Pass == 1 && !HaveLabel (Addr) &&
136 /* Check if we must create a label */
137 ((Flags & flGenLabel) != 0 ||
138 ((Flags & flUseLabel) != 0 && Addr >= CodeStart && Addr <= CodeEnd))) {
140 /* As a special case, handle ranges with tables or similar. Within
141 ** such a range with a granularity > 1, do only generate dependent
142 ** labels for all addresses but the first one. Be sure to generate
143 ** a label for the start of the range, however.
145 attr_t Style = GetStyleAttr (Addr);
146 unsigned Granularity = GetGranularity (Style);
148 if (Granularity == 1) {
149 /* Just add the label */
153 /* THIS CODE IS A MESS AND WILL FAIL ON SEVERAL CONDITIONS! ### */
156 /* Search for the start of the range or the last non dependent
157 ** label in the range.
161 unsigned LabelAddr = Addr;
162 while (LabelAddr > CodeStart) {
164 if (Style != GetStyleAttr (LabelAddr-1)) {
165 /* End of range reached */
169 LabelAttr = GetLabelAttr (LabelAddr);
170 if ((LabelAttr & (atIntLabel|atExtLabel)) != 0) {
171 /* The address has an internal or external label */
176 /* If the proposed label address doesn't have a label, define one */
177 if ((GetLabelAttr (LabelAddr) & (atIntLabel|atExtLabel)) == 0) {
178 AddIntLabel (LabelAddr);
181 /* Create the label */
182 Offs = Addr - LabelAddr;
186 AddDepLabel (Addr, atIntLabel, GetLabelName (LabelAddr), Offs);
194 /*****************************************************************************/
196 /*****************************************************************************/
200 void OH_Illegal (const OpcDesc* D attribute ((unused)))
207 void OH_Accumulator (const OpcDesc* D)
214 void OH_Implicit (const OpcDesc* D)
217 LineComment (PC, D->Size);
223 void OH_Immediate (const OpcDesc* D)
225 OneLine (D, "#$%02X", GetCodeByte (PC+1));
230 void OH_ImmediateWord (const OpcDesc* D)
232 OneLine (D, "#$%04X", GetCodeWord (PC+1));
237 void OH_Direct (const OpcDesc* D)
239 /* Get the operand */
240 unsigned Addr = GetCodeByte (PC+1);
242 /* Generate a label in pass 1 */
243 GenerateLabel (D->Flags, Addr);
245 /* Output the line */
246 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
251 void OH_DirectX (const OpcDesc* D)
253 /* Get the operand */
254 unsigned Addr = GetCodeByte (PC+1);
256 /* Generate a label in pass 1 */
257 GenerateLabel (D->Flags, Addr);
259 /* Output the line */
260 OneLine (D, "%s,x", GetAddrArg (D->Flags, Addr));
265 void OH_DirectY (const OpcDesc* D)
267 /* Get the operand */
268 unsigned Addr = GetCodeByte (PC+1);
270 /* Generate a label in pass 1 */
271 GenerateLabel (D->Flags, Addr);
273 /* Output the line */
274 OneLine (D, "%s,y", GetAddrArg (D->Flags, Addr));
279 void OH_Absolute (const OpcDesc* D)
281 /* Get the operand */
282 unsigned Addr = GetCodeWord (PC+1);
284 /* Generate a label in pass 1 */
285 GenerateLabel (D->Flags, Addr);
287 /* Output the line */
288 OneLine (D, "%s%s", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
293 void OH_AbsoluteX (const OpcDesc* D)
295 /* Get the operand */
296 unsigned Addr = GetCodeWord (PC+1);
298 /* Generate a label in pass 1 */
299 GenerateLabel (D->Flags, Addr);
301 /* Output the line */
302 OneLine (D, "%s%s,x", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
307 void OH_AbsoluteY (const OpcDesc* D)
309 /* Get the operand */
310 unsigned Addr = GetCodeWord (PC+1);
312 /* Generate a label in pass 1 */
313 GenerateLabel (D->Flags, Addr);
315 /* Output the line */
316 OneLine (D, "%s%s,y", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
321 void OH_AbsoluteLong (const OpcDesc* D attribute ((unused)))
323 Error ("Not implemented");
328 void OH_AbsoluteLongX (const OpcDesc* D attribute ((unused)))
330 Error ("Not implemented");
335 void OH_Relative (const OpcDesc* D)
337 /* Get the operand */
338 signed char Offs = GetCodeByte (PC+1);
340 /* Calculate the target address */
341 unsigned Addr = (((int) PC+2) + Offs) & 0xFFFF;
343 /* Generate a label in pass 1 */
344 GenerateLabel (D->Flags, Addr);
346 /* Output the line */
347 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
352 void OH_RelativeLong (const OpcDesc* D attribute ((unused)))
354 Error ("Not implemented");
359 void OH_RelativeLong4510 (const OpcDesc* D attribute ((unused)))
361 /* Get the operand */
362 signed short Offs = GetCodeWord (PC+1);
364 /* Calculate the target address */
365 unsigned Addr = (((int) PC+2) + Offs) & 0xFFFF;
367 /* Generate a label in pass 1 */
368 GenerateLabel (D->Flags, Addr);
370 /* Output the line */
371 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
376 void OH_DirectIndirect (const OpcDesc* D)
378 /* Get the operand */
379 unsigned Addr = GetCodeByte (PC+1);
381 /* Generate a label in pass 1 */
382 GenerateLabel (D->Flags, Addr);
384 /* Output the line */
385 OneLine (D, "(%s)", GetAddrArg (D->Flags, Addr));
390 void OH_DirectIndirectY (const OpcDesc* D)
392 /* Get the operand */
393 unsigned Addr = GetCodeByte (PC+1);
395 /* Generate a label in pass 1 */
396 GenerateLabel (D->Flags, Addr);
398 /* Output the line */
399 OneLine (D, "(%s),y", GetAddrArg (D->Flags, Addr));
404 void OH_DirectIndirectZ (const OpcDesc* D)
406 /* Get the operand */
407 unsigned Addr = GetCodeByte (PC+1);
409 /* Generate a label in pass 1 */
410 GenerateLabel (D->Flags, Addr);
412 /* Output the line */
413 OneLine (D, "(%s),z", GetAddrArg (D->Flags, Addr));
418 void OH_DirectXIndirect (const OpcDesc* D)
420 /* Get the operand */
421 unsigned Addr = GetCodeByte (PC+1);
423 /* Generate a label in pass 1 */
424 GenerateLabel (D->Flags, Addr);
426 /* Output the line */
427 OneLine (D, "(%s,x)", GetAddrArg (D->Flags, Addr));
432 void OH_AbsoluteIndirect (const OpcDesc* D)
434 /* Get the operand */
435 unsigned Addr = GetCodeWord (PC+1);
437 /* Generate a label in pass 1 */
438 GenerateLabel (D->Flags, Addr);
440 /* Output the line */
441 OneLine (D, "(%s)", GetAddrArg (D->Flags, Addr));
446 void OH_BitBranch (const OpcDesc* D)
450 /* Get the operands */
451 unsigned char TestAddr = GetCodeByte (PC+1);
452 signed char BranchOffs = GetCodeByte (PC+2);
454 /* Calculate the target address for the branch */
455 unsigned BranchAddr = (((int) PC+3) + BranchOffs) & 0xFFFF;
457 /* Generate labels in pass 1. The bit branch codes are special in that
458 ** they don't really match the remainder of the 6502 instruction set (they
459 ** are a Rockwell addon), so we must pass additional flags as direct
460 ** value to the second GenerateLabel call.
462 GenerateLabel (D->Flags, TestAddr);
463 GenerateLabel (flLabel, BranchAddr);
465 /* Make a copy of an operand, so that
466 ** the other operand can't overwrite it.
467 ** [GetAddrArg() uses a statically-stored buffer.]
469 BranchLabel = xstrdup (GetAddrArg (flLabel, BranchAddr));
471 /* Output the line */
472 OneLine (D, "%s,%s", GetAddrArg (D->Flags, TestAddr), BranchLabel);
479 void OH_ImmediateDirect (const OpcDesc* D)
481 /* Get the operand */
482 unsigned Addr = GetCodeByte (PC+2);
484 /* Generate a label in pass 1 */
485 GenerateLabel (D->Flags, Addr);
487 /* Output the line */
488 OneLine (D, "#$%02X,%s", GetCodeByte (PC+1), GetAddrArg (D->Flags, Addr));
493 void OH_ImmediateDirectX (const OpcDesc* D)
495 /* Get the operand */
496 unsigned Addr = GetCodeByte (PC+2);
498 /* Generate a label in pass 1 */
499 GenerateLabel (D->Flags, Addr);
501 /* Output the line */
502 OneLine (D, "#$%02X,%s,x", GetCodeByte (PC+1), GetAddrArg (D->Flags, Addr));
507 void OH_ImmediateAbsolute (const OpcDesc* D)
509 /* Get the operand */
510 unsigned Addr = GetCodeWord (PC+2);
512 /* Generate a label in pass 1 */
513 GenerateLabel (D->Flags, Addr);
515 /* Output the line */
516 OneLine (D, "#$%02X,%s%s", GetCodeByte (PC+1), GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
521 void OH_ImmediateAbsoluteX (const OpcDesc* D)
523 /* Get the operand */
524 unsigned Addr = GetCodeWord (PC+2);
526 /* Generate a label in pass 1 */
527 GenerateLabel (D->Flags, Addr);
529 /* Output the line */
530 OneLine (D, "#$%02X,%s%s,x", GetCodeByte (PC+1), GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
535 void OH_StackRelative (const OpcDesc* D attribute ((unused)))
537 Error ("Not implemented");
542 void OH_DirectIndirectLongX (const OpcDesc* D attribute ((unused)))
544 Error ("Not implemented");
549 void OH_StackRelativeIndirectY (const OpcDesc* D attribute ((unused)))
551 /* Output the line */
552 OneLine (D, "($%02X,s),y", GetCodeByte (PC+1));
557 void OH_StackRelativeIndirectY4510 (const OpcDesc* D attribute ((unused)))
559 /* Output the line */
560 OneLine (D, "($%02X,sp),y", GetCodeByte (PC+1));
565 void OH_DirectIndirectLong (const OpcDesc* D attribute ((unused)))
567 Error ("Not implemented");
572 void OH_DirectIndirectLongY (const OpcDesc* D attribute ((unused)))
574 Error ("Not implemented");
579 void OH_BlockMove (const OpcDesc* D)
583 /* Get source operand */
584 unsigned Src = GetCodeWord (PC+1);
585 /* Get destination operand */
586 unsigned Dst = GetCodeWord (PC+3);
588 /* Generate a label in pass 1 */
589 GenerateLabel (D->Flags, Src);
590 GenerateLabel (D->Flags, Dst);
592 /* Make a copy of an operand, so that
593 ** the other operand can't overwrite it.
594 ** [GetAddrArg() uses a statically-stored buffer.]
596 DstLabel = xstrdup (GetAddrArg (D->Flags, Dst));
598 /* Output the line */
599 OneLine (D, "%s%s,%s%s,$%04X",
600 GetAbsOverride (D->Flags, Src), GetAddrArg (D->Flags, Src),
601 GetAbsOverride (D->Flags, Dst), DstLabel,
609 void OH_AbsoluteXIndirect (const OpcDesc* D attribute ((unused)))
611 /* Get the operand */
612 unsigned Addr = GetCodeWord (PC+1);
614 /* Generate a label in pass 1 */
615 GenerateLabel (D->Flags, Addr);
617 /* Output the line */
618 OneLine (D, "(%s,x)", GetAddrArg (D->Flags, Addr));
623 void OH_DirectImmediate (const OpcDesc* D)
625 /* Get the operand */
626 unsigned Addr = GetCodeByte (PC+1);
628 /* Generate a label in pass 1 */
629 GenerateLabel (D->Flags, Addr);
631 /* Output the line */
632 OneLine (D, "%s, #$%02X", GetAddrArg (D->Flags, Addr), GetCodeByte (PC+2));
637 void OH_ZeroPageBit (const OpcDesc* D)
639 unsigned Bit = GetCodeByte (PC) >> 5;
640 unsigned Addr = GetCodeByte (PC+1);
642 /* Generate a label in pass 1 */
643 GenerateLabel (D->Flags, Addr);
645 /* Output the line */
646 OneLine (D, "%01X,%s", Bit, GetAddrArg (D->Flags, Addr));
651 void OH_AccumulatorBit (const OpcDesc* D)
653 unsigned Bit = GetCodeByte (PC) >> 5;
655 /* Output the line */
656 OneLine (D, "%01X,a", Bit);
661 void OH_AccumulatorBitBranch (const OpcDesc* D)
663 unsigned Bit = GetCodeByte (PC) >> 5;
664 signed char BranchOffs = GetCodeByte (PC+1);
666 /* Calculate the target address for the branch */
667 unsigned BranchAddr = (((int) PC+3) + BranchOffs) & 0xFFFF;
669 /* Generate labels in pass 1 */
670 GenerateLabel (flLabel, BranchAddr);
672 /* Output the line */
673 OneLine (D, "%01X,a,%s", Bit, GetAddrArg (flLabel, BranchAddr));
678 void OH_JmpDirectIndirect (const OpcDesc* D)
680 OH_DirectIndirect (D);
681 if (NewlineAfterJMP) {
689 void OH_SpecialPage (const OpcDesc* D)
691 /* Get the operand */
692 unsigned Addr = 0xFF00 + GetCodeByte (PC+1);
694 /* Generate a label in pass 1 */
695 GenerateLabel (D->Flags, Addr);
697 /* OneLine (D, "$FF%02X", (CodeByte (PC+1)); */
698 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
703 void OH_Rts (const OpcDesc* D)
706 if (NewlineAfterRTS) {
714 void OH_JmpAbsolute (const OpcDesc* D)
717 if (NewlineAfterJMP) {
725 void OH_JmpAbsoluteIndirect (const OpcDesc* D)
727 OH_AbsoluteIndirect (D);
728 if (NewlineAfterJMP) {
736 void OH_JmpAbsoluteXIndirect (const OpcDesc* D)
738 OH_AbsoluteXIndirect (D);
739 if (NewlineAfterJMP) {