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 | } |
778 | |