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 static unsigned short SubroutineParamSize[0x10000];
56 /*****************************************************************************/
57 /* Helper functions */
58 /*****************************************************************************/
62 static void Mnemonic (const char* M)
63 /* Indent and output a mnemonic */
71 static void OneLine (const OpcDesc* D, const char* Arg, ...) attribute ((format(printf, 2, 3)));
72 static void OneLine (const OpcDesc* D, const char* Arg, ...)
73 /* Output one line with the given mnemonic and argument */
83 xvsprintf (Buf, sizeof (Buf), Arg, ap);
88 /* Add the code stuff as comment */
89 LineComment (PC, D->Size);
97 static const char* GetAbsOverride (unsigned Flags, unsigned Addr)
98 /* If the instruction requires an abs override modifier, return the necessary
99 ** string, otherwise return the empty string.
102 if ((Flags & flAbsOverride) != 0 && Addr < 0x100) {
111 static const char* GetAddrArg (unsigned Flags, unsigned Addr)
112 /* Return an address argument - a label if we have one, or the address itself */
114 const char* Label = 0;
115 if (Flags & flUseLabel) {
116 Label = GetLabel (Addr, PC);
121 static char Buf [32];
123 xsprintf (Buf, sizeof (Buf), "$%02X", Addr);
125 xsprintf (Buf, sizeof (Buf), "$%04X", Addr);
133 static void GenerateLabel (unsigned Flags, unsigned Addr)
134 /* Generate a label in pass one if requested */
136 /* Generate labels in pass #1, and only if we don't have a label already */
137 if (Pass == 1 && !HaveLabel (Addr) &&
138 /* Check if we must create a label */
139 ((Flags & flGenLabel) != 0 ||
140 ((Flags & flUseLabel) != 0 && Addr >= CodeStart && Addr <= CodeEnd))) {
142 /* As a special case, handle ranges with tables or similar. Within
143 ** such a range with a granularity > 1, do only generate dependent
144 ** labels for all addresses but the first one. Be sure to generate
145 ** a label for the start of the range, however.
147 attr_t Style = GetStyleAttr (Addr);
148 unsigned Granularity = GetGranularity (Style);
150 if (Granularity == 1) {
151 /* Just add the label */
155 /* THIS CODE IS A MESS AND WILL FAIL ON SEVERAL CONDITIONS! ### */
158 /* Search for the start of the range or the last non dependent
159 ** label in the range.
163 unsigned LabelAddr = Addr;
164 while (LabelAddr > CodeStart) {
166 if (Style != GetStyleAttr (LabelAddr-1)) {
167 /* End of range reached */
171 LabelAttr = GetLabelAttr (LabelAddr);
172 if ((LabelAttr & (atIntLabel|atExtLabel)) != 0) {
173 /* The address has an internal or external label */
178 /* If the proposed label address doesn't have a label, define one */
179 if ((GetLabelAttr (LabelAddr) & (atIntLabel|atExtLabel)) == 0) {
180 AddIntLabel (LabelAddr);
183 /* Create the label */
184 Offs = Addr - LabelAddr;
188 AddDepLabel (Addr, atIntLabel, GetLabelName (LabelAddr), Offs);
196 /*****************************************************************************/
198 /*****************************************************************************/
202 void OH_Illegal (const OpcDesc* D attribute ((unused)))
209 void OH_Accumulator (const OpcDesc* D)
216 void OH_Implicit (const OpcDesc* D)
219 LineComment (PC, D->Size);
225 void OH_Immediate (const OpcDesc* D)
227 OneLine (D, "#$%02X", GetCodeByte (PC+1));
232 void OH_ImmediateWord (const OpcDesc* D)
234 OneLine (D, "#$%04X", GetCodeWord (PC+1));
239 void OH_Direct (const OpcDesc* D)
241 /* Get the operand */
242 unsigned Addr = GetCodeByte (PC+1);
244 /* Generate a label in pass 1 */
245 GenerateLabel (D->Flags, Addr);
247 /* Output the line */
248 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
253 void OH_DirectX (const OpcDesc* D)
255 /* Get the operand */
256 unsigned Addr = GetCodeByte (PC+1);
258 /* Generate a label in pass 1 */
259 GenerateLabel (D->Flags, Addr);
261 /* Output the line */
262 OneLine (D, "%s,x", GetAddrArg (D->Flags, Addr));
267 void OH_DirectY (const OpcDesc* D)
269 /* Get the operand */
270 unsigned Addr = GetCodeByte (PC+1);
272 /* Generate a label in pass 1 */
273 GenerateLabel (D->Flags, Addr);
275 /* Output the line */
276 OneLine (D, "%s,y", GetAddrArg (D->Flags, Addr));
281 void OH_Absolute (const OpcDesc* D)
283 /* Get the operand */
284 unsigned Addr = GetCodeWord (PC+1);
286 /* Generate a label in pass 1 */
287 GenerateLabel (D->Flags, Addr);
289 /* Output the line */
290 OneLine (D, "%s%s", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
295 void OH_AbsoluteX (const OpcDesc* D)
297 /* Get the operand */
298 unsigned Addr = GetCodeWord (PC+1);
300 /* Generate a label in pass 1 */
301 GenerateLabel (D->Flags, Addr);
303 /* Output the line */
304 OneLine (D, "%s%s,x", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
309 void OH_AbsoluteY (const OpcDesc* D)
311 /* Get the operand */
312 unsigned Addr = GetCodeWord (PC+1);
314 /* Generate a label in pass 1 */
315 GenerateLabel (D->Flags, Addr);
317 /* Output the line */
318 OneLine (D, "%s%s,y", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
323 void OH_AbsoluteLong (const OpcDesc* D attribute ((unused)))
325 Error ("Not implemented");
330 void OH_AbsoluteLongX (const OpcDesc* D attribute ((unused)))
332 Error ("Not implemented");
337 void OH_Relative (const OpcDesc* D)
339 /* Get the operand */
340 signed char Offs = GetCodeByte (PC+1);
342 /* Calculate the target address */
343 unsigned Addr = (((int) PC+2) + Offs) & 0xFFFF;
345 /* Generate a label in pass 1 */
346 GenerateLabel (D->Flags, Addr);
348 /* Output the line */
349 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
354 void OH_RelativeLong (const OpcDesc* D attribute ((unused)))
356 Error ("Not implemented");
361 void OH_RelativeLong4510 (const OpcDesc* D attribute ((unused)))
363 /* Get the operand */
364 signed short Offs = GetCodeWord (PC+1);
366 /* Calculate the target address */
367 unsigned Addr = (((int) PC+2) + Offs) & 0xFFFF;
369 /* Generate a label in pass 1 */
370 GenerateLabel (D->Flags, Addr);
372 /* Output the line */
373 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
378 void OH_DirectIndirect (const OpcDesc* D)
380 /* Get the operand */
381 unsigned Addr = GetCodeByte (PC+1);
383 /* Generate a label in pass 1 */
384 GenerateLabel (D->Flags, Addr);
386 /* Output the line */
387 OneLine (D, "(%s)", GetAddrArg (D->Flags, Addr));
392 void OH_DirectIndirectY (const OpcDesc* D)
394 /* Get the operand */
395 unsigned Addr = GetCodeByte (PC+1);
397 /* Generate a label in pass 1 */
398 GenerateLabel (D->Flags, Addr);
400 /* Output the line */
401 OneLine (D, "(%s),y", GetAddrArg (D->Flags, Addr));
406 void OH_DirectIndirectZ (const OpcDesc* D)
408 /* Get the operand */
409 unsigned Addr = GetCodeByte (PC+1);
411 /* Generate a label in pass 1 */
412 GenerateLabel (D->Flags, Addr);
414 /* Output the line */
415 OneLine (D, "(%s),z", GetAddrArg (D->Flags, Addr));
420 void OH_DirectXIndirect (const OpcDesc* D)
422 /* Get the operand */
423 unsigned Addr = GetCodeByte (PC+1);
425 /* Generate a label in pass 1 */
426 GenerateLabel (D->Flags, Addr);
428 /* Output the line */
429 OneLine (D, "(%s,x)", GetAddrArg (D->Flags, Addr));
434 void OH_AbsoluteIndirect (const OpcDesc* D)
436 /* Get the operand */
437 unsigned Addr = GetCodeWord (PC+1);
439 /* Generate a label in pass 1 */
440 GenerateLabel (D->Flags, Addr);
442 /* Output the line */
443 OneLine (D, "(%s)", GetAddrArg (D->Flags, Addr));
448 void OH_BitBranch (const OpcDesc* D)
452 /* Get the operands */
453 unsigned char TestAddr = GetCodeByte (PC+1);
454 signed char BranchOffs = GetCodeByte (PC+2);
456 /* Calculate the target address for the branch */
457 unsigned BranchAddr = (((int) PC+3) + BranchOffs) & 0xFFFF;
459 /* Generate labels in pass 1. The bit branch codes are special in that
460 ** they don't really match the remainder of the 6502 instruction set (they
461 ** are a Rockwell addon), so we must pass additional flags as direct
462 ** value to the second GenerateLabel call.
464 GenerateLabel (D->Flags, TestAddr);
465 GenerateLabel (flLabel, BranchAddr);
467 /* Make a copy of an operand, so that
468 ** the other operand can't overwrite it.
469 ** [GetAddrArg() uses a statically-stored buffer.]
471 BranchLabel = xstrdup (GetAddrArg (flLabel, BranchAddr));
473 /* Output the line */
474 OneLine (D, "%s,%s", GetAddrArg (D->Flags, TestAddr), BranchLabel);
481 void OH_ImmediateDirect (const OpcDesc* D)
483 /* Get the operand */
484 unsigned Addr = GetCodeByte (PC+2);
486 /* Generate a label in pass 1 */
487 GenerateLabel (D->Flags, Addr);
489 /* Output the line */
490 OneLine (D, "#$%02X,%s", GetCodeByte (PC+1), GetAddrArg (D->Flags, Addr));
495 void OH_ImmediateDirectX (const OpcDesc* D)
497 /* Get the operand */
498 unsigned Addr = GetCodeByte (PC+2);
500 /* Generate a label in pass 1 */
501 GenerateLabel (D->Flags, Addr);
503 /* Output the line */
504 OneLine (D, "#$%02X,%s,x", GetCodeByte (PC+1), GetAddrArg (D->Flags, Addr));
509 void OH_ImmediateAbsolute (const OpcDesc* D)
511 /* Get the operand */
512 unsigned Addr = GetCodeWord (PC+2);
514 /* Generate a label in pass 1 */
515 GenerateLabel (D->Flags, Addr);
517 /* Output the line */
518 OneLine (D, "#$%02X,%s%s", GetCodeByte (PC+1), GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
523 void OH_ImmediateAbsoluteX (const OpcDesc* D)
525 /* Get the operand */
526 unsigned Addr = GetCodeWord (PC+2);
528 /* Generate a label in pass 1 */
529 GenerateLabel (D->Flags, Addr);
531 /* Output the line */
532 OneLine (D, "#$%02X,%s%s,x", GetCodeByte (PC+1), GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
537 void OH_StackRelative (const OpcDesc* D attribute ((unused)))
539 Error ("Not implemented");
544 void OH_DirectIndirectLongX (const OpcDesc* D attribute ((unused)))
546 Error ("Not implemented");
551 void OH_StackRelativeIndirectY (const OpcDesc* D attribute ((unused)))
553 /* Output the line */
554 OneLine (D, "($%02X,s),y", GetCodeByte (PC+1));
559 void OH_StackRelativeIndirectY4510 (const OpcDesc* D attribute ((unused)))
561 /* Output the line */
562 OneLine (D, "($%02X,sp),y", GetCodeByte (PC+1));
567 void OH_DirectIndirectLong (const OpcDesc* D attribute ((unused)))
569 Error ("Not implemented");
574 void OH_DirectIndirectLongY (const OpcDesc* D attribute ((unused)))
576 Error ("Not implemented");
581 void OH_BlockMove (const OpcDesc* D)
585 /* Get source operand */
586 unsigned Src = GetCodeWord (PC+1);
587 /* Get destination operand */
588 unsigned Dst = GetCodeWord (PC+3);
590 /* Generate a label in pass 1 */
591 GenerateLabel (D->Flags, Src);
592 GenerateLabel (D->Flags, Dst);
594 /* Make a copy of an operand, so that
595 ** the other operand can't overwrite it.
596 ** [GetAddrArg() uses a statically-stored buffer.]
598 DstLabel = xstrdup (GetAddrArg (D->Flags, Dst));
600 /* Output the line */
601 OneLine (D, "%s%s,%s%s,$%04X",
602 GetAbsOverride (D->Flags, Src), GetAddrArg (D->Flags, Src),
603 GetAbsOverride (D->Flags, Dst), DstLabel,
611 void OH_AbsoluteXIndirect (const OpcDesc* D attribute ((unused)))
613 /* Get the operand */
614 unsigned Addr = GetCodeWord (PC+1);
616 /* Generate a label in pass 1 */
617 GenerateLabel (D->Flags, Addr);
619 /* Output the line */
620 OneLine (D, "(%s,x)", GetAddrArg (D->Flags, Addr));
625 void OH_DirectImmediate (const OpcDesc* D)
627 /* Get the operand */
628 unsigned Addr = GetCodeByte (PC+1);
630 /* Generate a label in pass 1 */
631 GenerateLabel (D->Flags, Addr);
633 /* Output the line */
634 OneLine (D, "%s, #$%02X", GetAddrArg (D->Flags, Addr), GetCodeByte (PC+2));
639 void OH_ZeroPageBit (const OpcDesc* D)
641 unsigned Bit = GetCodeByte (PC) >> 5;
642 unsigned Addr = GetCodeByte (PC+1);
644 /* Generate a label in pass 1 */
645 GenerateLabel (D->Flags, Addr);
647 /* Output the line */
648 OneLine (D, "%01X,%s", Bit, GetAddrArg (D->Flags, Addr));
653 void OH_AccumulatorBit (const OpcDesc* D)
655 unsigned Bit = GetCodeByte (PC) >> 5;
657 /* Output the line */
658 OneLine (D, "%01X,a", Bit);
663 void OH_AccumulatorBitBranch (const OpcDesc* D)
665 unsigned Bit = GetCodeByte (PC) >> 5;
666 signed char BranchOffs = GetCodeByte (PC+1);
668 /* Calculate the target address for the branch */
669 unsigned BranchAddr = (((int) PC+3) + BranchOffs) & 0xFFFF;
671 /* Generate labels in pass 1 */
672 GenerateLabel (flLabel, BranchAddr);
674 /* Output the line */
675 OneLine (D, "%01X,a,%s", Bit, GetAddrArg (flLabel, BranchAddr));
680 void OH_JmpDirectIndirect (const OpcDesc* D)
682 OH_DirectIndirect (D);
683 if (NewlineAfterJMP) {
691 void OH_SpecialPage (const OpcDesc* D)
693 /* Get the operand */
694 unsigned Addr = 0xFF00 + GetCodeByte (PC+1);
696 /* Generate a label in pass 1 */
697 GenerateLabel (D->Flags, Addr);
699 /* OneLine (D, "$FF%02X", (CodeByte (PC+1)); */
700 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
705 void OH_Rts (const OpcDesc* D)
708 if (NewlineAfterRTS) {
716 void OH_JmpAbsolute (const OpcDesc* D)
719 if (NewlineAfterJMP) {
727 void OH_JmpAbsoluteIndirect (const OpcDesc* D)
729 OH_AbsoluteIndirect (D);
730 if (NewlineAfterJMP) {
738 void OH_JmpAbsoluteXIndirect (const OpcDesc* D)
740 OH_AbsoluteXIndirect (D);
741 if (NewlineAfterJMP) {
749 void OH_JsrAbsolute (const OpcDesc* D)
751 unsigned ParamSize = SubroutineParamSize[GetCodeWord (PC+1)];
754 unsigned RemainingBytes;
757 RemainingBytes = GetRemainingBytes ();
758 if (RemainingBytes < ParamSize) {
759 ParamSize = RemainingBytes;
761 BytesLeft = ParamSize;
762 while (BytesLeft > 0) {
763 unsigned Chunk = (BytesLeft > BytesPerLine) ? BytesPerLine : BytesLeft;
764 DataByteLine (Chunk);
774 void SetSubroutineParamSize (unsigned Addr, unsigned Size)
776 SubroutineParamSize[Addr] = Size;