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