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_Direct (const OpcDesc* D)
232 /* Get the operand */
233 unsigned Addr = GetCodeByte (PC+1);
235 /* Generate a label in pass 1 */
236 GenerateLabel (D->Flags, Addr);
238 /* Output the line */
239 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
244 void OH_DirectX (const OpcDesc* D)
246 /* Get the operand */
247 unsigned Addr = GetCodeByte (PC+1);
249 /* Generate a label in pass 1 */
250 GenerateLabel (D->Flags, Addr);
252 /* Output the line */
253 OneLine (D, "%s,x", GetAddrArg (D->Flags, Addr));
258 void OH_DirectY (const OpcDesc* D)
260 /* Get the operand */
261 unsigned Addr = GetCodeByte (PC+1);
263 /* Generate a label in pass 1 */
264 GenerateLabel (D->Flags, Addr);
266 /* Output the line */
267 OneLine (D, "%s,y", GetAddrArg (D->Flags, Addr));
272 void OH_Absolute (const OpcDesc* D)
274 /* Get the operand */
275 unsigned Addr = GetCodeWord (PC+1);
277 /* Generate a label in pass 1 */
278 GenerateLabel (D->Flags, Addr);
280 /* Output the line */
281 OneLine (D, "%s%s", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
286 void OH_AbsoluteX (const OpcDesc* D)
288 /* Get the operand */
289 unsigned Addr = GetCodeWord (PC+1);
291 /* Generate a label in pass 1 */
292 GenerateLabel (D->Flags, Addr);
294 /* Output the line */
295 OneLine (D, "%s%s,x", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
300 void OH_AbsoluteY (const OpcDesc* D)
302 /* Get the operand */
303 unsigned Addr = GetCodeWord (PC+1);
305 /* Generate a label in pass 1 */
306 GenerateLabel (D->Flags, Addr);
308 /* Output the line */
309 OneLine (D, "%s%s,y", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
314 void OH_AbsoluteLong (const OpcDesc* D attribute ((unused)))
316 Error ("Not implemented");
321 void OH_AbsoluteLongX (const OpcDesc* D attribute ((unused)))
323 Error ("Not implemented");
328 void OH_Relative (const OpcDesc* D)
330 /* Get the operand */
331 signed char Offs = GetCodeByte (PC+1);
333 /* Calculate the target address */
334 unsigned Addr = (((int) PC+2) + Offs) & 0xFFFF;
336 /* Generate a label in pass 1 */
337 GenerateLabel (D->Flags, Addr);
339 /* Output the line */
340 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
345 void OH_RelativeLong (const OpcDesc* D attribute ((unused)))
347 Error ("Not implemented");
352 void OH_DirectIndirect (const OpcDesc* D)
354 /* Get the operand */
355 unsigned Addr = GetCodeByte (PC+1);
357 /* Generate a label in pass 1 */
358 GenerateLabel (D->Flags, Addr);
360 /* Output the line */
361 OneLine (D, "(%s)", GetAddrArg (D->Flags, Addr));
366 void OH_DirectIndirectY (const OpcDesc* D)
368 /* Get the operand */
369 unsigned Addr = GetCodeByte (PC+1);
371 /* Generate a label in pass 1 */
372 GenerateLabel (D->Flags, Addr);
374 /* Output the line */
375 OneLine (D, "(%s),y", GetAddrArg (D->Flags, Addr));
380 void OH_DirectXIndirect (const OpcDesc* D)
382 /* Get the operand */
383 unsigned Addr = GetCodeByte (PC+1);
385 /* Generate a label in pass 1 */
386 GenerateLabel (D->Flags, Addr);
388 /* Output the line */
389 OneLine (D, "(%s,x)", GetAddrArg (D->Flags, Addr));
394 void OH_AbsoluteIndirect (const OpcDesc* D)
396 /* Get the operand */
397 unsigned Addr = GetCodeWord (PC+1);
399 /* Generate a label in pass 1 */
400 GenerateLabel (D->Flags, Addr);
402 /* Output the line */
403 OneLine (D, "(%s)", GetAddrArg (D->Flags, Addr));
408 void OH_BitBranch (const OpcDesc* D)
412 /* Get the operands */
413 unsigned char TestAddr = GetCodeByte (PC+1);
414 signed char BranchOffs = GetCodeByte (PC+2);
416 /* Calculate the target address for the branch */
417 unsigned BranchAddr = (((int) PC+3) + BranchOffs) & 0xFFFF;
419 /* Generate labels in pass 1. The bit branch codes are special in that
420 ** they don't really match the remainder of the 6502 instruction set (they
421 ** are a Rockwell addon), so we must pass additional flags as direct
422 ** value to the second GenerateLabel call.
424 GenerateLabel (D->Flags, TestAddr);
425 GenerateLabel (flLabel, BranchAddr);
427 /* Make a copy of an operand, so that
428 ** the other operand can't overwrite it.
429 ** [GetAddrArg() uses a statically-stored buffer.]
431 BranchLabel = xstrdup (GetAddrArg (flLabel, BranchAddr));
433 /* Output the line */
434 OneLine (D, "%s,%s", GetAddrArg (D->Flags, TestAddr), BranchLabel);
441 void OH_ImmediateDirect (const OpcDesc* D)
443 /* Get the operand */
444 unsigned Addr = GetCodeByte (PC+2);
446 /* Generate a label in pass 1 */
447 GenerateLabel (D->Flags, Addr);
449 /* Output the line */
450 OneLine (D, "#$%02X,%s", GetCodeByte (PC+1), GetAddrArg (D->Flags, Addr));
455 void OH_ImmediateDirectX (const OpcDesc* D)
457 /* Get the operand */
458 unsigned Addr = GetCodeByte (PC+2);
460 /* Generate a label in pass 1 */
461 GenerateLabel (D->Flags, Addr);
463 /* Output the line */
464 OneLine (D, "#$%02X,%s,x", GetCodeByte (PC+1), GetAddrArg (D->Flags, Addr));
469 void OH_ImmediateAbsolute (const OpcDesc* D)
471 /* Get the operand */
472 unsigned Addr = GetCodeWord (PC+2);
474 /* Generate a label in pass 1 */
475 GenerateLabel (D->Flags, Addr);
477 /* Output the line */
478 OneLine (D, "#$%02X,%s%s", GetCodeByte (PC+1), GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
483 void OH_ImmediateAbsoluteX (const OpcDesc* D)
485 /* Get the operand */
486 unsigned Addr = GetCodeWord (PC+2);
488 /* Generate a label in pass 1 */
489 GenerateLabel (D->Flags, Addr);
491 /* Output the line */
492 OneLine (D, "#$%02X,%s%s,x", GetCodeByte (PC+1), GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
497 void OH_StackRelative (const OpcDesc* D attribute ((unused)))
499 Error ("Not implemented");
504 void OH_DirectIndirectLongX (const OpcDesc* D attribute ((unused)))
506 Error ("Not implemented");
511 void OH_StackRelativeIndirectY (const OpcDesc* D attribute ((unused)))
513 Error ("Not implemented");
518 void OH_DirectIndirectLong (const OpcDesc* D attribute ((unused)))
520 Error ("Not implemented");
525 void OH_DirectIndirectLongY (const OpcDesc* D attribute ((unused)))
527 Error ("Not implemented");
532 void OH_BlockMove (const OpcDesc* D)
536 /* Get source operand */
537 unsigned Src = GetCodeWord (PC+1);
538 /* Get destination operand */
539 unsigned Dst = GetCodeWord (PC+3);
541 /* Generate a label in pass 1 */
542 GenerateLabel (D->Flags, Src);
543 GenerateLabel (D->Flags, Dst);
545 /* Make a copy of an operand, so that
546 ** the other operand can't overwrite it.
547 ** [GetAddrArg() uses a statically-stored buffer.]
549 DstLabel = xstrdup (GetAddrArg (D->Flags, Dst));
551 /* Output the line */
552 OneLine (D, "%s%s,%s%s,$%04X",
553 GetAbsOverride (D->Flags, Src), GetAddrArg (D->Flags, Src),
554 GetAbsOverride (D->Flags, Dst), DstLabel,
562 void OH_AbsoluteXIndirect (const OpcDesc* D attribute ((unused)))
564 /* Get the operand */
565 unsigned Addr = GetCodeWord (PC+1);
567 /* Generate a label in pass 1 */
568 GenerateLabel (D->Flags, Addr);
570 /* Output the line */
571 OneLine (D, "(%s,x)", GetAddrArg (D->Flags, Addr));
576 void OH_DirectImmediate (const OpcDesc* D)
578 /* Get the operand */
579 unsigned Addr = GetCodeByte (PC+1);
581 /* Generate a label in pass 1 */
582 GenerateLabel (D->Flags, Addr);
584 /* Output the line */
585 OneLine (D, "%s, #$%02X", GetAddrArg (D->Flags, Addr), GetCodeByte (PC+2));
590 void OH_ZeroPageBit (const OpcDesc* D)
592 unsigned Bit = GetCodeByte (PC) >> 5;
593 unsigned Addr = GetCodeByte (PC+1);
595 /* Generate a label in pass 1 */
596 GenerateLabel (D->Flags, Addr);
598 /* Output the line */
599 OneLine (D, "%01X,%s", Bit, GetAddrArg (D->Flags, Addr));
604 void OH_AccumulatorBit (const OpcDesc* D)
606 unsigned Bit = GetCodeByte (PC) >> 5;
608 /* Output the line */
609 OneLine (D, "%01X,a", Bit);
614 void OH_AccumulatorBitBranch (const OpcDesc* D)
616 unsigned Bit = GetCodeByte (PC) >> 5;
617 signed char BranchOffs = GetCodeByte (PC+1);
619 /* Calculate the target address for the branch */
620 unsigned BranchAddr = (((int) PC+3) + BranchOffs) & 0xFFFF;
622 /* Generate labels in pass 1 */
623 GenerateLabel (flLabel, BranchAddr);
625 /* Output the line */
626 OneLine (D, "%01X,a,%s", Bit, GetAddrArg (flLabel, BranchAddr));
631 void OH_JmpDirectIndirect (const OpcDesc* D)
633 OH_DirectIndirect (D);
634 if (NewlineAfterJMP) {
642 void OH_SpecialPage (const OpcDesc* D)
644 /* Get the operand */
645 unsigned Addr = 0xFF00 + GetCodeByte (PC+1);
647 /* Generate a label in pass 1 */
648 GenerateLabel (D->Flags, Addr);
650 /* OneLine (D, "$FF%02X", (CodeByte (PC+1)); */
651 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
656 void OH_Rts (const OpcDesc* D)
659 if (NewlineAfterRTS) {
667 void OH_JmpAbsolute (const OpcDesc* D)
670 if (NewlineAfterJMP) {
678 void OH_JmpAbsoluteIndirect (const OpcDesc* D)
680 OH_AbsoluteIndirect (D);
681 if (NewlineAfterJMP) {
689 void OH_JmpAbsoluteXIndirect (const OpcDesc* D)
691 OH_AbsoluteXIndirect (D);
692 if (NewlineAfterJMP) {