1/*****************************************************************************/
2/* */
3/* handler.c */
4/* */
5/* Opcode handler functions for the disassembler */
6/* */
7/* */
8/* */
9/* (C) 2000-2011, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
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. */
18/* */
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: */
22/* */
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 */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36#include <stdarg.h>
37
38/* common */
39#include "xmalloc.h"
40#include "xsprintf.h"
41
42/* da65 */
43#include "attrtab.h"
44#include "code.h"
45#include "error.h"
46#include "global.h"
47#include "handler.h"
48#include "labels.h"
49#include "opctable.h"
50#include "output.h"
51
52
53
54static unsigned short SubroutineParamSize[0x10000];
55
56/*****************************************************************************/
57/* Helper functions */
58/*****************************************************************************/
59
60
61
62static void Mnemonic (const char* M)
63/* Indent and output a mnemonic */
64{
65 Indent (MCol);
66 Output ("%s", M);
67}
68
69
70
71static void OneLine (const OpcDesc* D, const char* Arg, ...) attribute ((format(printf, 2, 3)));
72static void OneLine (const OpcDesc* D, const char* Arg, ...)
73/* Output one line with the given mnemonic and argument */
74{
75 char Buf [256];
76 va_list ap;
77
78 /* Mnemonic */
79 Mnemonic (D->Mnemo);
80
81 /* Argument */
82 va_start (ap, Arg);
83 xvsprintf (Buf, sizeof (Buf), Arg, ap);
84 va_end (ap);
85 Indent (ACol);
86 Output ("%s", Buf);
87
88 /* Add the code stuff as comment */
89 LineComment (PC, D->Size);
90
91 /* End the line */
92 LineFeed ();
93}
94
95
96
97static 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.
100*/
101{
102 if ((Flags & flAbsOverride) != 0 && Addr < 0x100) {
103 return "a:";
104 } else {
105 return "";
106 }
107}
108
109
110
111static const char* GetAddrArg (unsigned Flags, unsigned Addr)
112/* Return an address argument - a label if we have one, or the address itself */
113{
114 const char* Label = 0;
115 if (Flags & flUseLabel) {
116 Label = GetLabel (Addr, PC);
117 }
118 if (Label) {
119 return Label;
120 } else {
121 static char Buf [32];
122 if (Addr < 0x100) {
123 xsprintf (Buf, sizeof (Buf), "$%02X", Addr);
124 } else {
125 xsprintf (Buf, sizeof (Buf), "$%04X", Addr);
126 }
127 return Buf;
128 }
129}
130
131
132
133static void GenerateLabel (unsigned Flags, unsigned Addr)
134/* Generate a label in pass one if requested */
135{
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))) {
141
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.
146 */
147 attr_t Style = GetStyleAttr (Addr);
148 unsigned Granularity = GetGranularity (Style);
149
150 if (Granularity == 1) {
151 /* Just add the label */
152 AddIntLabel (Addr);
153 } else {
154
155 /* THIS CODE IS A MESS AND WILL FAIL ON SEVERAL CONDITIONS! ### */
156
157
158 /* Search for the start of the range or the last non dependent
159 ** label in the range.
160 */
161 unsigned Offs;
162 attr_t LabelAttr;
163 unsigned LabelAddr = Addr;
164 while (LabelAddr > CodeStart) {
165
166 if (Style != GetStyleAttr (LabelAddr-1)) {
167 /* End of range reached */
168 break;
169 }
170 --LabelAddr;
171 LabelAttr = GetLabelAttr (LabelAddr);
172 if ((LabelAttr & (atIntLabel|atExtLabel)) != 0) {
173 /* The address has an internal or external label */
174 break;
175 }
176 }
177
178 /* If the proposed label address doesn't have a label, define one */
179 if ((GetLabelAttr (LabelAddr) & (atIntLabel|atExtLabel)) == 0) {
180 AddIntLabel (LabelAddr);
181 }
182
183 /* Create the label */
184 Offs = Addr - LabelAddr;
185 if (Offs == 0) {
186 AddIntLabel (Addr);
187 } else {
188 AddDepLabel (Addr, atIntLabel, GetLabelName (LabelAddr), Offs);
189 }
190 }
191 }
192}
193
194
195
196/*****************************************************************************/
197/* Code */
198/*****************************************************************************/
199
200
201
202void OH_Illegal (const OpcDesc* D attribute ((unused)))
203{
204 DataByteLine (1);
205}
206
207
208
209void OH_Accumulator (const OpcDesc* D)
210{
211 OneLine (D, "a");
212}
213
214
215
216void OH_Implicit (const OpcDesc* D)
217{
218 Mnemonic (D->Mnemo);
219 LineComment (PC, D->Size);
220 LineFeed ();
221}
222
223
224
225void OH_Immediate (const OpcDesc* D)
226{
227 OneLine (D, "#$%02X", GetCodeByte (PC+1));
228}
229
230
231
232void OH_ImmediateWord (const OpcDesc* D)
233{
234 OneLine (D, "#$%04X", GetCodeWord (PC+1));
235}
236
237
238
239void OH_Direct (const OpcDesc* D)
240{
241 /* Get the operand */
242 unsigned Addr = GetCodeByte (PC+1);
243
244 /* Generate a label in pass 1 */
245 GenerateLabel (D->Flags, Addr);
246
247 /* Output the line */
248 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
249}
250
251
252
253void OH_DirectX (const OpcDesc* D)
254{
255 /* Get the operand */
256 unsigned Addr = GetCodeByte (PC+1);
257
258 /* Generate a label in pass 1 */
259 GenerateLabel (D->Flags, Addr);
260
261 /* Output the line */
262 OneLine (D, "%s,x", GetAddrArg (D->Flags, Addr));
263}
264
265
266
267void OH_DirectY (const OpcDesc* D)
268{
269 /* Get the operand */
270 unsigned Addr = GetCodeByte (PC+1);
271
272 /* Generate a label in pass 1 */
273 GenerateLabel (D->Flags, Addr);
274
275 /* Output the line */
276 OneLine (D, "%s,y", GetAddrArg (D->Flags, Addr));
277}
278
279
280
281void OH_Absolute (const OpcDesc* D)
282{
283 /* Get the operand */
284 unsigned Addr = GetCodeWord (PC+1);
285
286 /* Generate a label in pass 1 */
287 GenerateLabel (D->Flags, Addr);
288
289 /* Output the line */
290 OneLine (D, "%s%s", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
291}
292
293
294
295void OH_AbsoluteX (const OpcDesc* D)
296{
297 /* Get the operand */
298 unsigned Addr = GetCodeWord (PC+1);
299
300 /* Generate a label in pass 1 */
301 GenerateLabel (D->Flags, Addr);
302
303 /* Output the line */
304 OneLine (D, "%s%s,x", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
305}
306
307
308
309void OH_AbsoluteY (const OpcDesc* D)
310{
311 /* Get the operand */
312 unsigned Addr = GetCodeWord (PC+1);
313
314 /* Generate a label in pass 1 */
315 GenerateLabel (D->Flags, Addr);
316
317 /* Output the line */
318 OneLine (D, "%s%s,y", GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
319}
320
321
322
323void OH_AbsoluteLong (const OpcDesc* D attribute ((unused)))
324{
325 Error ("Not implemented");
326}
327
328
329
330void OH_AbsoluteLongX (const OpcDesc* D attribute ((unused)))
331{
332 Error ("Not implemented");
333}
334
335
336
337void OH_Relative (const OpcDesc* D)
338{
339 /* Get the operand */
340 signed char Offs = GetCodeByte (PC+1);
341
342 /* Calculate the target address */
343 unsigned Addr = (((int) PC+2) + Offs) & 0xFFFF;
344
345 /* Generate a label in pass 1 */
346 GenerateLabel (D->Flags, Addr);
347
348 /* Output the line */
349 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
350}
351
352
353
354void OH_RelativeLong (const OpcDesc* D attribute ((unused)))
355{
356 Error ("Not implemented");
357}
358
359
360
361void OH_RelativeLong4510 (const OpcDesc* D attribute ((unused)))
362{
363 /* Get the operand */
364 signed short Offs = GetCodeWord (PC+1);
365
366 /* Calculate the target address */
367 unsigned Addr = (((int) PC+2) + Offs) & 0xFFFF;
368
369 /* Generate a label in pass 1 */
370 GenerateLabel (D->Flags, Addr);
371
372 /* Output the line */
373 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
374}
375
376
377
378void OH_DirectIndirect (const OpcDesc* D)
379{
380 /* Get the operand */
381 unsigned Addr = GetCodeByte (PC+1);
382
383 /* Generate a label in pass 1 */
384 GenerateLabel (D->Flags, Addr);
385
386 /* Output the line */
387 OneLine (D, "(%s)", GetAddrArg (D->Flags, Addr));
388}
389
390
391
392void OH_DirectIndirectY (const OpcDesc* D)
393{
394 /* Get the operand */
395 unsigned Addr = GetCodeByte (PC+1);
396
397 /* Generate a label in pass 1 */
398 GenerateLabel (D->Flags, Addr);
399
400 /* Output the line */
401 OneLine (D, "(%s),y", GetAddrArg (D->Flags, Addr));
402}
403
404
405
406void OH_DirectIndirectZ (const OpcDesc* D)
407{
408 /* Get the operand */
409 unsigned Addr = GetCodeByte (PC+1);
410
411 /* Generate a label in pass 1 */
412 GenerateLabel (D->Flags, Addr);
413
414 /* Output the line */
415 OneLine (D, "(%s),z", GetAddrArg (D->Flags, Addr));
416}
417
418
419
420void OH_DirectXIndirect (const OpcDesc* D)
421{
422 /* Get the operand */
423 unsigned Addr = GetCodeByte (PC+1);
424
425 /* Generate a label in pass 1 */
426 GenerateLabel (D->Flags, Addr);
427
428 /* Output the line */
429 OneLine (D, "(%s,x)", GetAddrArg (D->Flags, Addr));
430}
431
432
433
434void OH_AbsoluteIndirect (const OpcDesc* D)
435{
436 /* Get the operand */
437 unsigned Addr = GetCodeWord (PC+1);
438
439 /* Generate a label in pass 1 */
440 GenerateLabel (D->Flags, Addr);
441
442 /* Output the line */
443 OneLine (D, "(%s)", GetAddrArg (D->Flags, Addr));
444}
445
446
447
448void OH_BitBranch (const OpcDesc* D)
449{
450 char* BranchLabel;
451
452 /* Get the operands */
453 unsigned char TestAddr = GetCodeByte (PC+1);
454 signed char BranchOffs = GetCodeByte (PC+2);
455
456 /* Calculate the target address for the branch */
457 unsigned BranchAddr = (((int) PC+3) + BranchOffs) & 0xFFFF;
458
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.
463 */
464 GenerateLabel (D->Flags, TestAddr);
465 GenerateLabel (flLabel, BranchAddr);
466
467 /* Make a copy of an operand, so that
468 ** the other operand can't overwrite it.
469 ** [GetAddrArg() uses a statically-stored buffer.]
470 */
471 BranchLabel = xstrdup (GetAddrArg (flLabel, BranchAddr));
472
473 /* Output the line */
474 OneLine (D, "%s,%s", GetAddrArg (D->Flags, TestAddr), BranchLabel);
475
476 xfree (BranchLabel);
477}
478
479
480
481void OH_ImmediateDirect (const OpcDesc* D)
482{
483 /* Get the operand */
484 unsigned Addr = GetCodeByte (PC+2);
485
486 /* Generate a label in pass 1 */
487 GenerateLabel (D->Flags, Addr);
488
489 /* Output the line */
490 OneLine (D, "#$%02X,%s", GetCodeByte (PC+1), GetAddrArg (D->Flags, Addr));
491}
492
493
494
495void OH_ImmediateDirectX (const OpcDesc* D)
496{
497 /* Get the operand */
498 unsigned Addr = GetCodeByte (PC+2);
499
500 /* Generate a label in pass 1 */
501 GenerateLabel (D->Flags, Addr);
502
503 /* Output the line */
504 OneLine (D, "#$%02X,%s,x", GetCodeByte (PC+1), GetAddrArg (D->Flags, Addr));
505}
506
507
508
509void OH_ImmediateAbsolute (const OpcDesc* D)
510{
511 /* Get the operand */
512 unsigned Addr = GetCodeWord (PC+2);
513
514 /* Generate a label in pass 1 */
515 GenerateLabel (D->Flags, Addr);
516
517 /* Output the line */
518 OneLine (D, "#$%02X,%s%s", GetCodeByte (PC+1), GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
519}
520
521
522
523void OH_ImmediateAbsoluteX (const OpcDesc* D)
524{
525 /* Get the operand */
526 unsigned Addr = GetCodeWord (PC+2);
527
528 /* Generate a label in pass 1 */
529 GenerateLabel (D->Flags, Addr);
530
531 /* Output the line */
532 OneLine (D, "#$%02X,%s%s,x", GetCodeByte (PC+1), GetAbsOverride (D->Flags, Addr), GetAddrArg (D->Flags, Addr));
533}
534
535
536
537void OH_StackRelative (const OpcDesc* D attribute ((unused)))
538{
539 Error ("Not implemented");
540}
541
542
543
544void OH_DirectIndirectLongX (const OpcDesc* D attribute ((unused)))
545{
546 Error ("Not implemented");
547}
548
549
550
551void OH_StackRelativeIndirectY (const OpcDesc* D attribute ((unused)))
552{
553 /* Output the line */
554 OneLine (D, "($%02X,s),y", GetCodeByte (PC+1));
555}
556
557
558
559void OH_StackRelativeIndirectY4510 (const OpcDesc* D attribute ((unused)))
560{
561 /* Output the line */
562 OneLine (D, "($%02X,sp),y", GetCodeByte (PC+1));
563}
564
565
566
567void OH_DirectIndirectLong (const OpcDesc* D attribute ((unused)))
568{
569 Error ("Not implemented");
570}
571
572
573
574void OH_DirectIndirectLongY (const OpcDesc* D attribute ((unused)))
575{
576 Error ("Not implemented");
577}
578
579
580
581void OH_BlockMove (const OpcDesc* D)
582{
583 char* DstLabel;
584
585 /* Get source operand */
586 unsigned Src = GetCodeWord (PC+1);
587 /* Get destination operand */
588 unsigned Dst = GetCodeWord (PC+3);
589
590 /* Generate a label in pass 1 */
591 GenerateLabel (D->Flags, Src);
592 GenerateLabel (D->Flags, Dst);
593
594 /* Make a copy of an operand, so that
595 ** the other operand can't overwrite it.
596 ** [GetAddrArg() uses a statically-stored buffer.]
597 */
598 DstLabel = xstrdup (GetAddrArg (D->Flags, Dst));
599
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,
604 GetCodeWord (PC+5));
605
606 xfree (DstLabel);
607}
608
609
610
611void OH_AbsoluteXIndirect (const OpcDesc* D attribute ((unused)))
612{
613 /* Get the operand */
614 unsigned Addr = GetCodeWord (PC+1);
615
616 /* Generate a label in pass 1 */
617 GenerateLabel (D->Flags, Addr);
618
619 /* Output the line */
620 OneLine (D, "(%s,x)", GetAddrArg (D->Flags, Addr));
621}
622
623
624
625void OH_DirectImmediate (const OpcDesc* D)
626{
627 /* Get the operand */
628 unsigned Addr = GetCodeByte (PC+1);
629
630 /* Generate a label in pass 1 */
631 GenerateLabel (D->Flags, Addr);
632
633 /* Output the line */
634 OneLine (D, "%s, #$%02X", GetAddrArg (D->Flags, Addr), GetCodeByte (PC+2));
635}
636
637
638
639void OH_ZeroPageBit (const OpcDesc* D)
640{
641 unsigned Bit = GetCodeByte (PC) >> 5;
642 unsigned Addr = GetCodeByte (PC+1);
643
644 /* Generate a label in pass 1 */
645 GenerateLabel (D->Flags, Addr);
646
647 /* Output the line */
648 OneLine (D, "%01X,%s", Bit, GetAddrArg (D->Flags, Addr));
649}
650
651
652
653void OH_AccumulatorBit (const OpcDesc* D)
654{
655 unsigned Bit = GetCodeByte (PC) >> 5;
656
657 /* Output the line */
658 OneLine (D, "%01X,a", Bit);
659}
660
661
662
663void OH_AccumulatorBitBranch (const OpcDesc* D)
664{
665 unsigned Bit = GetCodeByte (PC) >> 5;
666 signed char BranchOffs = GetCodeByte (PC+1);
667
668 /* Calculate the target address for the branch */
669 unsigned BranchAddr = (((int) PC+3) + BranchOffs) & 0xFFFF;
670
671 /* Generate labels in pass 1 */
672 GenerateLabel (flLabel, BranchAddr);
673
674 /* Output the line */
675 OneLine (D, "%01X,a,%s", Bit, GetAddrArg (flLabel, BranchAddr));
676}
677
678
679
680void OH_JmpDirectIndirect (const OpcDesc* D)
681{
682 OH_DirectIndirect (D);
683 if (NewlineAfterJMP) {
684 LineFeed ();
685 }
686 SeparatorLine ();
687}
688
689
690
691void OH_SpecialPage (const OpcDesc* D)
692{
693 /* Get the operand */
694 unsigned Addr = 0xFF00 + GetCodeByte (PC+1);
695
696 /* Generate a label in pass 1 */
697 GenerateLabel (D->Flags, Addr);
698
699 /* OneLine (D, "$FF%02X", (CodeByte (PC+1)); */
700 OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
701}
702
703
704
705void OH_Rts (const OpcDesc* D)
706{
707 OH_Implicit (D);
708 if (NewlineAfterRTS) {
709 LineFeed ();
710 }
711 SeparatorLine();
712}
713
714
715
716void OH_JmpAbsolute (const OpcDesc* D)
717{
718 OH_Absolute (D);
719 if (NewlineAfterJMP) {
720 LineFeed ();
721 }
722 SeparatorLine ();
723}
724
725
726
727void OH_JmpAbsoluteIndirect (const OpcDesc* D)
728{
729 OH_AbsoluteIndirect (D);
730 if (NewlineAfterJMP) {
731 LineFeed ();
732 }
733 SeparatorLine ();
734}
735
736
737
738void OH_JmpAbsoluteXIndirect (const OpcDesc* D)
739{
740 OH_AbsoluteXIndirect (D);
741 if (NewlineAfterJMP) {
742 LineFeed ();
743 }
744 SeparatorLine ();
745}
746
747
748
749void OH_JsrAbsolute (const OpcDesc* D)
750{
751 unsigned ParamSize = SubroutineParamSize[GetCodeWord (PC+1)];
752 OH_Absolute (D);
753 if (ParamSize > 0) {
754 unsigned RemainingBytes;
755 unsigned BytesLeft;
756 PC += D->Size;
757 RemainingBytes = GetRemainingBytes ();
758 if (RemainingBytes < ParamSize) {
759 ParamSize = RemainingBytes;
760 }
761 BytesLeft = ParamSize;
762 while (BytesLeft > 0) {
763 unsigned Chunk = (BytesLeft > BytesPerLine) ? BytesPerLine : BytesLeft;
764 DataByteLine (Chunk);
765 BytesLeft -= Chunk;
766 PC += Chunk;
767 }
768 PC -= D->Size;
769 }
770}
771
772
773
774void SetSubroutineParamSize (unsigned Addr, unsigned Size)
775{
776 SubroutineParamSize[Addr] = Size;
777}
778