]> git.sur5r.net Git - cc65/blob - src/da65/handler.c
Style and alignment fixes.
[cc65] / src / da65 / handler.c
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
54 static unsigned short SubroutineParamSize[0x10000];
55
56 /*****************************************************************************/
57 /*                             Helper functions                              */
58 /*****************************************************************************/
59
60
61
62 static void Mnemonic (const char* M)
63 /* Indent and output a mnemonic */
64 {
65     Indent (MCol);
66     Output ("%s", M);
67 }
68
69
70
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 */
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
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.
100 */
101 {
102     if ((Flags & flAbsOverride) != 0 && Addr < 0x100) {
103         return "a:";
104     } else {
105         return "";
106     }
107 }
108
109
110
111 static 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
133 static 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
202 void OH_Illegal (const OpcDesc* D attribute ((unused)))
203 {
204     DataByteLine (1);
205 }
206
207
208
209 void OH_Accumulator (const OpcDesc* D)
210 {
211     OneLine (D, "a");
212 }
213
214
215
216 void OH_Implicit (const OpcDesc* D)
217 {
218     Mnemonic (D->Mnemo);
219     LineComment (PC, D->Size);
220     LineFeed ();
221 }
222
223
224
225 void OH_Immediate (const OpcDesc* D)
226 {
227     OneLine (D, "#$%02X", GetCodeByte (PC+1));
228 }
229
230
231
232 void OH_ImmediateWord (const OpcDesc* D)
233 {
234     OneLine (D, "#$%04X", GetCodeWord (PC+1));
235 }
236
237
238
239 void 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
253 void 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
267 void 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
281 void 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
295 void 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
309 void 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
323 void OH_AbsoluteLong (const OpcDesc* D attribute ((unused)))
324 {
325     Error ("Not implemented");
326 }
327
328
329
330 void OH_AbsoluteLongX (const OpcDesc* D attribute ((unused)))
331 {
332     Error ("Not implemented");
333 }
334
335
336
337 void 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
354 void OH_RelativeLong (const OpcDesc* D attribute ((unused)))
355 {
356     Error ("Not implemented");
357 }
358
359
360
361 void 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
378 void 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
392 void 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
406 void 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
420 void 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
434 void 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
448 void 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
481 void 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
495 void 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
509 void 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
523 void 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
537 void OH_StackRelative (const OpcDesc* D attribute ((unused)))
538 {
539     Error ("Not implemented");
540 }
541
542
543
544 void OH_DirectIndirectLongX (const OpcDesc* D attribute ((unused)))
545 {
546     Error ("Not implemented");
547 }
548
549
550
551 void 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
559 void 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
567 void OH_DirectIndirectLong (const OpcDesc* D attribute ((unused)))
568 {
569     Error ("Not implemented");
570 }
571
572
573
574 void OH_DirectIndirectLongY (const OpcDesc* D attribute ((unused)))
575 {
576     Error ("Not implemented");
577 }
578
579
580
581 void 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
611 void 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
625 void 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
639 void 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
653 void 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
663 void 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
680 void OH_JmpDirectIndirect (const OpcDesc* D)
681 {
682     OH_DirectIndirect (D);
683     if (NewlineAfterJMP) {
684         LineFeed ();
685     }
686     SeparatorLine ();
687 }
688
689
690
691 void 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
705 void OH_Rts (const OpcDesc* D)
706 {
707     OH_Implicit (D);
708     if (NewlineAfterRTS) {
709         LineFeed ();
710     }
711     SeparatorLine();
712 }
713
714
715
716 void OH_JmpAbsolute (const OpcDesc* D)
717 {
718     OH_Absolute (D);
719     if (NewlineAfterJMP) {
720         LineFeed ();
721     }
722     SeparatorLine ();
723 }
724
725
726
727 void OH_JmpAbsoluteIndirect (const OpcDesc* D)
728 {
729     OH_AbsoluteIndirect (D);
730     if (NewlineAfterJMP) {
731         LineFeed ();
732     }
733     SeparatorLine ();
734 }
735
736
737
738 void OH_JmpAbsoluteXIndirect (const OpcDesc* D)
739 {
740     OH_AbsoluteXIndirect (D);
741     if (NewlineAfterJMP) {
742         LineFeed ();
743     }
744     SeparatorLine ();
745 }
746
747
748
749 void 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
774 void SetSubroutineParamSize (unsigned Addr, unsigned Size)
775 {
776     SubroutineParamSize[Addr] = Size;
777 }