1 /*
2 Z80 Disassembler Module v2.0
3
4 Copyright 1996-2002 Mark Incley.
5 */
6
7 #include <time.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13
14 #include "dissz80p.h"
15
16
LookOpcode(DISZ80 * d,int offset)17 int LookOpcode(DISZ80 *d, int offset)
18 {
19 assert(d != NULL);
20 if (d->flags & DISFLAG_CALLBACK)
21 return d->Z80MemCB((void *)d->Z80MemBase,
22 ((d->PC + offset) & 0xffff));
23 return d->Z80MemBase[(d->PC + offset) & 0xffff];
24 }
25
26
GetNextOpCode(DISZ80 * d)27 int GetNextOpCode(DISZ80 *d)
28 {
29 char buf[8];
30
31 assert(d != NULL);
32
33 if (d->flags & DISFLAG_CALLBACK)
34 d->op = d->Z80MemCB((void *)d->Z80MemBase, d->PC++);
35 else
36 d->op = d->Z80MemBase[d->PC++];
37
38 if (d->PC == 0)
39 d->haveWrapped = TRUE;
40
41 if (d->currentPass == DPASS_WRITE && d->labelledOutput == FALSE)
42 {
43 sprintf(buf, "%02x", (BYTE)d->op);
44 strcat(d->hexDisBuf, buf);
45 }
46
47 d->bytesProcessed++;
48 return d->op;
49 }
50
dZ80_GetVersionString(void)51 char *dZ80_GetVersionString(void)
52 {
53 return VersionString;
54 }
55
56 /*
57 void dZ80_SetDefaultOptions(DISZ80 *d)
58
59 Set the default radix (hex), comment marker and DB directive string.
60 */
61
dZ80_SetDefaultOptions(DISZ80 * d)62 void dZ80_SetDefaultOptions(DISZ80 *d)
63 {
64 assert(d != NULL);
65
66 /* Standard comment and DB */
67 strcpy(d->layoutComment, "; ");
68 strcpy(d->layoutDefineByte, "db");
69
70 /* Hex by default */
71 dZ80_SetRadix(d, DRADIX_DEFAULT);
72 return;
73 }
74
75
dZ80_InheritRadix(DISZ80 * dst,DISZ80 * src)76 void dZ80_InheritRadix(DISZ80 *dst, DISZ80 *src)
77 {
78 assert(dst != NULL && src != NULL);
79 assert(dst != src);
80
81 dst->layoutRadix = src->layoutRadix;
82 strcpy(dst->layoutComment, src->layoutComment);
83 strcpy(dst->layoutDefineByte, src->layoutDefineByte);
84 strcpy(dst->layoutNumberPrefix, src->layoutNumberPrefix);
85 strcpy(dst->layoutNumberSuffix, src->layoutNumberSuffix);
86 return;
87 }
88
dZ80_SetRadix(DISZ80 * d,int radix)89 void dZ80_SetRadix(DISZ80 *d, int radix)
90 {
91 assert(d != NULL);
92 assert(radix >= 0 && radix < DRADIX_TOTAL);
93
94 d->layoutNumberPrefix[0] = d->layoutNumberSuffix[0] = 0;
95 d->layoutRadix = radix;
96
97 switch(radix)
98 {
99 case DRADIX_OCTAL:
100 strcpy(d->layoutNumberPrefix, "0");
101 break;
102
103 case DRADIX_DECIMAL:
104 break;
105
106 case DRADIX_HEX:
107 strcpy(d->layoutNumberPrefix, "{");
108 strcpy(d->layoutNumberSuffix, "h");
109 break;
110 }
111
112 return;
113 }
114
115
116
PrepareDisInstruction(DISZ80 * d)117 void PrepareDisInstruction(DISZ80 *d)
118 {
119 assert(d != NULL);
120
121 d->hexDisBuf[0] = d->disBuf[0] = d->commentBuf[0] = 0;
122 d->Z80Flags = d->numRecursions = 0; /* Clear and IX/IY prefixes, etc. */
123 d->lineCmd = 0; /* Clear out line commands */
124 d->disBufIndex = 0; /* Point to the start of the line again */
125 d->haveTabbed = FALSE;
126 d->lastPC = d->PC;
127 return;
128 }
129
dZ80_Disassemble(DISZ80 * d)130 int dZ80_Disassemble(DISZ80 *d)
131 {
132 int i, err, skipped;
133 char buf[256], num1[16], num2[16];
134
135 assert(d != NULL);
136
137 if (d == NULL)
138 return DERR_INVALIDPARAMS;
139
140 if ((d->flags & DISFLAG_CALLBACK) && (d->memCB == NULL))
141 return DERR_INVALIDPARAMS;
142 else if (d->mem0Start == NULL)
143 return DERR_INVALIDPARAMS;
144
145 d->createdRefOK = FALSE;
146 d->numInstructions = 0;
147 d->currentPass = DPASS_INIT;
148 d->Z80MemBase = d->mem0Start;
149 d->Z80MemCB = d->memCB;
150 d->totalPasses = 1;
151 d->labelledOutput = FALSE;
152 d->outStream = NULL;
153 d->fnMap = NULL;
154
155 if ( (!(d->flags & DISFLAG_SINGLE)) && (d->outFileName[0] == 0) )
156 d->dissingToConsole = TRUE;
157 else
158 d->dissingToConsole = FALSE;
159
160 /* Has labelled output been requested? */
161 if (d->flags & DISFLAG_LABELLED)
162 {
163 d->totalPasses = 2;
164 d->labelledOutput = TRUE;
165 /* Switch off the opcode and address dump */
166 d->flags &= ~(DISFLAG_ADDRDUMP | DISFLAG_OPCODEDUMP);
167 }
168
169 for(i=0; i < DISREF_TOTAL; i++)
170 {
171 d->pRefHead[i] = NULL;
172 d->numRefs[i] = 0;
173 }
174
175 d->disStart = d->start;
176 d->disEnd = d->end;
177
178 if (d->disEnd < d->disStart)
179 {
180 d->lastPC = d->disStart;
181 d->disStart = d->disEnd;
182 d->disEnd = d->lastPC;
183 }
184
185 d->bytesToProcess = ((DWORD)d->disEnd - (DWORD)d->disStart + 1) * d->totalPasses;
186 d->bytesProcessed = 0;
187
188 /*
189 2.0: Perform the single instruction disassembly now
190 */
191 if (d->flags & DISFLAG_SINGLE)
192 {
193 d->flags &= ~DISFLAG_ANYREF;
194 d->flags |= DISFLAG_QUIET;
195 d->currentPass = DPASS_WRITE;
196 StartPass(d);
197 DisassembleInstruction(d);
198 WriteDisLine(d, d->lastPC);
199 return DERR_NONE;
200 }
201
202 /*
203 We never get here if DISFLAG_SINGLE has been specified
204 */
205
206 if (!(d->flags & DISFLAG_QUIET))
207 {
208 sprintf(buf, " Input file: %s", d->srcFileName);
209 dZ80_ShowMsg(d, buf);
210
211 sprintf(buf, " Output file: %s", (d->outFileName[0]) ? d->outFileName : "(none)");
212 dZ80_ShowMsg(d, buf);
213
214 if (d->scriptFileName[0])
215 {
216 sprintf(buf, " Script file: %s", d->scriptFileName);
217 dZ80_ShowMsg(d, buf);
218 }
219
220 if (d->opMapFileName[0])
221 {
222 sprintf(buf, " Opcode Map file: %s", d->opMapFileName);
223 dZ80_ShowMsg(d, buf);
224 }
225
226 Make16BitNum(d, num1, d->disStart);
227 Make16BitNum(d, num2, d->disEnd);
228 sprintf(buf, "Disassembly range: %s - %s", num1, num2);
229 dZ80_ShowMsg(d, buf);
230
231 dZ80_ShowMsg(d, "");
232 }
233
234 /* 2.0: Opcode map file is allocated regardless of whether an opcode map file is loaded */
235 if ((err = PrepareOpMap(d)) != DERR_NONE)
236 {
237 DisZ80CleanUp(d);
238 return err;
239 }
240
241 /* 2.0: If we're using a script to trap opcodes, set it up now */
242 if ((err = InitOpcodeTraps(d)) != DERR_NONE)
243 {
244 DisZ80CleanUp(d);
245 return err;
246 }
247
248 /* Assembler output (2 passes) ? */
249 if (d->labelledOutput == TRUE)
250 {
251 if ((d->fnMap = AllocateMap(d, "Couldn't allocate memory for the function map.", Z80MEMSIZE)) == NULL)
252 {
253 DisZ80CleanUp(d);
254 return DERR_OUTOFMEM;
255 }
256
257 for (i=0; i < 8; i++)
258 FlagFn(d, i << 3); /* Flag the RST addresses */
259 }
260
261 /* If a destination file has been given, disassemble to file. */
262 if ((err = CreateOutputASMFile(d)) != DERR_NONE)
263 {
264 DisZ80CleanUp(d);
265 return err;
266 }
267
268 /* Draw the progress indicator */
269 DoProgress(d, TRUE);
270
271 /* Ok, at last, here's the disassembly loop! */
272 for (d->currentPass = d->totalPasses; d->currentPass > 0; d->currentPass--)
273 {
274 StartPass(d);
275
276 if (!(d->flags & DISFLAG_QUIET))
277 {
278 sprintf(buf, "Pass %d of %d", d->totalPasses - d->currentPass + 1, d->totalPasses);
279 dZ80_ShowMsg(d, buf);
280 }
281
282 while (WithinDisRange(d))
283 {
284 DoProgress(d, FALSE);
285
286 /* Check if we should skip this */
287 skipped = FALSE;
288 d->firstByte = (BYTE)LookOpcode(d, 0);
289
290 if (! ISCODEBYTE(d, d->PC))
291 {
292 skipped = TRUE;
293 AddToDisTabDB(d);
294 Make8BitNum(d, buf, GetNextOpCode(d));
295 AddToDis(d, buf);
296 }
297
298 /* Execute the pre-trap script and if we added an instruction */
299 if (!skipped)
300 {
301 if (ExecPreTrap(d))
302 continue;
303 /* And do the deeds */
304 DisassembleInstruction(d);
305 }
306
307 /* Write out the disline (where the disassembly is built up) */
308 err = WriteDisLine(d, d->lastPC);
309 if (err)
310 {
311 DisZ80CleanUp(d);
312 return err;
313 }
314
315 /* Execute any post trap */
316 if (!skipped)
317 ExecPostTrap(d);
318 } /* Next instruction */
319
320 DoProgress(d, TRUE);
321 } /* Next pass */
322
323 if (!(d->flags & DISFLAG_QUIET))
324 {
325 sprintf(buf, "\nDisassembled %u instructions.", d->numInstructions);
326 dZ80_ShowMsg(d, buf);
327 }
328
329 WriteReferenceFile(d);
330
331 DisZ80CleanUp(d);
332
333 return DERR_NONE; /* Disassembled OK */
334 }
335
336
WriteDisLine(DISZ80 * d,unsigned int Addr)337 int WriteDisLine(DISZ80 *d, unsigned int Addr)
338 {
339 int i;
340 char disLine[512], buf[128];
341
342 if (d->currentPass == DPASS_WRITE)
343 {
344 disLine[0] = 0;
345
346 /* 2.0 - Upper case the components separately */
347 if (d->flags & DISFLAG_UPPER)
348 {
349 dZ80_StringToUpper(d->hexDisBuf);
350 dZ80_StringToUpper(d->disBuf);
351 }
352
353 /* Add the instruction's address ? */
354 if (d->flags & DISFLAG_ADDRDUMP)
355 {
356 MakeLJustified16BitNum(d, buf, Addr);
357 strcat(buf, " ");
358 strcat(disLine, buf);
359 }
360
361 /* Add the hex dump? */
362 if (d->flags & DISFLAG_OPCODEDUMP)
363 {
364 sprintf(buf, "%-8s ", d->hexDisBuf);
365 strcat(disLine, buf);
366 }
367
368 /* Add the disassembly */
369 if (d->labelledOutput && IsFnUsed(d, Addr))
370 sprintf(disLine, "l%04x: ", Addr);
371 else
372 if ((d->flags & (DISFLAG_OPCODEDUMP | DISFLAG_ADDRDUMP)) == 0)
373 strcat(disLine, " ");
374
375 strcat(disLine, d->disBuf);
376
377
378 /* Add any comment */
379 if (d->commentBuf[0])
380 {
381 i = strlen(disLine);
382 if (i < COMMENTCOLUMN)
383 {
384 memset(buf, ' ', COMMENTCOLUMN-i);
385 buf[COMMENTCOLUMN - i] = 0;
386 strcat(disLine, buf);
387 }
388 strcat(disLine, d->commentBuf);
389 }
390
391 /* Finally, add the new-line */
392 strcat(disLine,"\n");
393
394 /* Really finally, process any line commands */
395 if (d->flags & DISFLAG_LINECOMMANDS)
396 {
397 if (d->lineCmd & LC_BLANKLINE)
398 strcat(disLine, "\n");
399 }
400
401 if (d->dissingToConsole)
402 {
403 printf("%s", disLine);
404 }
405 else
406 {
407 if (d->outStream != NULL)
408 {
409 if (!fwrite(disLine, strlen(disLine), 1, d->outStream))
410 {
411 DisZ80CleanUp(d);
412 return DERR_COULDNTWRITETOFILE;
413 }
414 }
415 }
416
417 } /* d->currentPass == DPASS_WRITE */
418
419 /* Increment the # instructions disassembled counter */
420 d->numInstructions++;
421
422 /* Note that if we're performing a single instruction disassembly, we do not want to
423 clear the buffers */
424 if (!(d->flags & DISFLAG_SINGLE))
425 PrepareDisInstruction(d);
426
427 return DERR_NONE;
428 }
429
430
431
432 /* Release allocated memory, close open files, etc.. */
433
DisZ80CleanUp(DISZ80 * d)434 void DisZ80CleanUp(DISZ80 *d)
435 {
436 int i;
437 DISREF *dr, *drLast;
438 DISREFADDR *ra, *raLast;
439
440 assert(d != NULL);
441
442 if (d->outStream != NULL)
443 {
444 fclose(d->outStream);
445 d->outStream = NULL;
446 }
447
448 for(i=0; i < DISREF_TOTAL; i++)
449 {
450 dr = d->pRefHead[i];
451 while(dr != NULL)
452 {
453 ra = dr->pRefAddrHead;
454 while (ra != NULL)
455 {
456 raLast = ra;
457 ra = ra->pNext;
458 free(raLast);
459 }
460 drLast = dr;
461 dr = dr->pNext;
462 free(drLast);
463 }
464 d->pRefHead[i] = NULL;
465 }
466
467 if (d->opMap != NULL)
468 {
469 free(d->opMap);
470 d->opMap = NULL;
471 }
472
473 if (d->fnMap != NULL)
474 {
475 free(d->fnMap);
476 d->fnMap = NULL;
477 }
478
479 if (d->pTrapMap != NULL)
480 {
481 free(d->pTrapMap);
482 d->pTrapMap = NULL;
483 }
484
485 ShutdownScripting(d);
486 return;
487 }
488
489
490 /* Time to disassemble an instruction */
491
DisassembleInstruction(DISZ80 * d)492 void DisassembleInstruction(DISZ80 *d)
493 {
494 int o;
495
496 if (++d->numRecursions > 3)
497 {
498 AddToDisUnknown(d, NULL);
499 return;
500 }
501
502 /* Get initial opcode */
503 o = GetNextOpCode(d);
504
505 switch (o)
506 {
507 case 0xcb: /* Disassemble the Rotates, SETs and RES's */
508 d->Z80Flags |= Z80CB;
509 DisCB(d);
510 return;
511
512 case 0xed:
513 if (d->cpuType == DCPU_Z80GB)
514 {
515 AddToDisUndocNop(d);
516 }
517 else
518 {
519 d->Z80Flags |= Z80ED;
520 DisED(d);
521 }
522 return;
523
524 case 0xdd:
525 if (d->cpuType == DCPU_Z80GB)
526 {
527 AddToDisUndocNop(d);
528 }
529 else
530 {
531 d->Z80Flags |= Z80IX; /* Signal IX prefix */
532 d->Z80Flags &= ~Z80IY; /* Clear IY prefix */
533 DisassembleInstruction(d);
534 }
535 return;
536
537 case 0xfd:
538 if (d->cpuType == DCPU_Z80GB)
539 {
540 AddToDisUndocNop(d);
541 }
542 else
543 {
544 d->Z80Flags |= Z80IY; /* Signal IY prefix */
545 d->Z80Flags &= ~Z80IX; /* Clear IX prefix */
546 DisassembleInstruction(d);
547 }
548 return;
549 }
550
551 d->realop = d->op;
552
553 if (o < 0x40)
554 {
555 Dis00to3F(d);
556 return;
557 }
558
559 if (o >= 0x40 && o <= 0x7f)
560 {
561 Dis40to7F(d); /* All the LD's */
562 return;
563 }
564
565 if (o >= 0x80 && o <= 0xbf)
566 {
567 Dis80toBF(d);
568 return;
569 }
570
571 if (o >= 0xc0)
572 {
573 DisC0toFF(d);
574 return;
575 }
576
577 AddToDisUnknown(d, NULL);
578 return;
579 }
580
581
DisCB(DISZ80 * d)582 void DisCB(DISZ80 *d)
583 {
584 char num[3];
585 int o, oi;
586
587 /*
588 If there's an IX IY prefix, then the displacement comes *BEFORE* the
589 final opcode. LD (IX+dd),nn is a similar case.
590 */
591
592 if (d->Z80Flags & Z80IXIY)
593 GetIXIYDisplacement(d);
594
595 o = GetNextOpCode(d);
596
597 /* Test for undocumented DDCB stuff */
598
599 if (d->Z80Flags & Z80IXIY)
600 if ((o & 7) != REG_HL)
601 {
602 DisDDCB(d);
603 return;
604 }
605
606 if (o < 0x40)
607 {
608 /* Do the rotates */
609 oi = o >> 3;
610 if ((oi == 6) && (d->cpuType == DCPU_Z80GB))
611 AddToDisTab(d, "swap");
612 else
613 AddToDisTab(d, (char *)CBRotType[oi & 7]);
614
615 AddToDisReg8(d, o, FALSE);
616 }
617 else
618 {
619 switch (o >> 6)
620 {
621 case 1:
622 AddToDisTab(d, "bit");
623 break;
624
625 case 2:
626 AddToDisTab(d, "res");
627 break;
628
629 case 3:
630 AddToDisTab(d, "set");
631 break;
632 }
633
634 num[0] = (char)('0'+ ((o >> 3) & 7));
635 num[1] = ',';
636 num[2] = 0;
637 AddToDis(d, num);
638
639 /* Finally, add the register component. */
640 AddToDisReg8(d, o, FALSE);
641 }
642 }
643
644
645 /* Decode the DDCB instruction */
646
DisDDCB(DISZ80 * d)647 void DisDDCB(DISZ80 *d)
648 {
649 char num[4];
650 int BitResSet;
651
652 if (d->op < 0x40)
653 {
654 /* Do the undocumented rotates */
655 AddToDisTabLD(d, "");
656 AddToDisReg8(d, d->op, REG_HL); /* REG_HL stops L->IXl, etc.. */
657 AddToDis(d, ",");
658 AddToDis(d, CBRotType[(d->op >> 3) & 7]);
659 AddToDis(d, " ");
660 AddToDisReg8(d, REG_HL, FALSE);
661 return;
662 }
663
664 BitResSet = d->op >> 6;
665
666 if (BitResSet >= 2)
667 {
668 AddToDisTabLD(d, "");
669 AddToDisReg8(d, d->op, REG_HL); /* REG_HL stops L->IXl, etc.. */
670 AddToDis(d, ",");
671 }
672
673 switch (BitResSet)
674 {
675 case 1:
676 AddToDisTab(d, "bit");
677 break;
678 case 2:
679 AddToDisTab(d, "res");
680 break;
681 case 3:
682 AddToDisTab(d, "set");
683 break;
684 }
685
686 num[0] = ' ';
687 num[1] = (char)('0'+ ((d->op >> 3) & 7));
688 num[2] = ',';
689 num[3] = 0;
690
691 AddToDis(d, num + (BitResSet < 2) );
692
693 /* Finally, add the register component. */
694 AddToDisReg8(d, REG_HL, FALSE);
695
696 if (BitResSet == 1)
697 AddToDisUndoc(d);
698
699 return;
700 }
701
702
DisED(DISZ80 * d)703 void DisED(DISZ80 *d)
704 {
705 int o;
706
707 o = GetNextOpCode(d);
708
709 if (o <= 0x3f)
710 if (DisED00to3F(d))
711 return;
712
713 if (o >= 0x40 && o <= 0x7f)
714 if (DisED40to7F(d))
715 return;
716
717 if (o >= 0x80 && o <= 0xbf)
718 if (DisED80toBF(d))
719 return;
720
721 /* Unknown EDxx opcode */
722 AddToDisUnknown(d, "Undocumented 8 T-State NOP");
723 return;
724 }
725
726 /* ED00 - ED3F are currently only Z180 instructions */
727
DisED00to3F(DISZ80 * d)728 int DisED00to3F(DISZ80 *d)
729 {
730 int r, bb;
731
732 if (d->cpuType < DCPU_Z180)
733 return FALSE;
734
735 bb = d->op & 7;
736 r = (d->op >> 3) & 7;
737
738 switch (bb)
739 {
740 case 0: /* ED 0x00 - 0x38 */
741 AddToDisTab(d, "in0");
742 AddToDis(d, Reg8Idx[r]);
743 AddToDis(d, ",(");
744 AddToDis8BitAbs(d, FALSE);
745 AddToDis(d, ")");
746 AddToDisCommentZ180(d);
747 return TRUE;
748
749 case 1: /* ED 0x01 - 0x39 */
750 AddToDisTab(d, "out0");
751 AddToDis(d, "(");
752 AddToDis8BitAbs(d, FALSE);
753 AddToDis(d, "),");
754 AddToDis(d, Reg8Idx[r]);
755 AddToDisCommentZ180(d);
756 return TRUE;
757
758 case 4: /* ED 0x04 - 0x3c */
759 AddToDisTab(d, "tst");
760 AddToDis(d, Reg8Idx[r]);
761 AddToDisCommentZ180(d);
762 return TRUE;
763 }
764
765 return FALSE;
766 }
767
768
DisED40to7F(DISZ80 * d)769 int DisED40to7F(DISZ80 *d)
770 {
771 char Address[16];
772 int EDop;
773
774 /* First, let's get those nasty special case opcodes. */
775
776 EDop = d->op;
777
778 switch (EDop)
779 {
780 case 0x76: /* This is SLP which clashes with the undocumented Z80's IM 1 */
781 if (d->cpuType >= DCPU_Z180)
782 {
783 AddToDisTab(d, "slp");
784 AddToDisCommentZ180(d);
785 return TRUE;
786 }
787 break;
788
789 case 0x4c: /* The Z180's MLT instructions */
790 case 0x5c:
791 case 0x6c:
792 case 0x7c:
793 if (d->cpuType < DCPU_Z180)
794 return FALSE;
795
796 AddToDisTab(d, "mlt");
797 AddToDis(d, Reg16Idx[(EDop >> 4) & 3]);
798 AddToDisCommentZ180(d);
799 return TRUE;
800
801 case 0x64: /* Z180's TST nn */
802 if (d->cpuType < DCPU_Z180)
803 return FALSE;
804
805 AddToDisTab(d, "tst");
806 AddToDis8BitAbs(d, FALSE);
807 AddToDisCommentZ180(d);
808 return TRUE;
809
810 case 0x74:
811 if (d->cpuType < DCPU_Z180)
812 return FALSE;
813
814 AddToDisTab(d, "tstio");
815 AddToDis(d, "(");
816 AddToDis8BitAbs(d, FALSE);
817 AddToDis(d, ")");
818 AddToDisCommentZ180(d);
819 return TRUE;
820
821 /* Back to the regular Z80's stuff */
822
823 case 0x45:
824 AddToDisTab(d, "retn");
825 MARKBLANKLINE;
826 return TRUE;
827
828 case 0x47:
829 AddToDisTabLD(d, "i,a");
830 return TRUE;
831
832 case 0x4d:
833 AddToDisTab(d, "reti");
834 MARKBLANKLINE;
835 return TRUE;
836
837 case 0x4f:
838 AddToDisTabLD(d, "r,a");
839 return TRUE;
840
841 case 0x57:
842 AddToDisTabLD(d, "a,i");
843 return TRUE;
844
845 case 0x5f:
846 AddToDisTabLD(d, "a,r");
847 return TRUE;
848
849 case 0x67:
850 AddToDisTab(d, "rrd");
851 return TRUE;
852
853 case 0x6f:
854 AddToDisTab(d, "rld");
855 return TRUE;
856 }
857
858 switch (EDop & 7)
859 {
860 case 0:
861 AddToDisTab(d, "in");
862 AddToDis(d, Reg8AFIdx[(EDop >> 3) & 7] );
863 AddToDis(d, ",(c)");
864 return TRUE;
865
866 case 1:
867 AddToDisTab(d, "out");
868 AddToDis(d, "(c),");
869 AddToDis(d, Reg8AFIdx[(EDop >> 3) & 7] );
870 return TRUE;
871
872 case 2:
873 AddToDisTab(d, (EDop & 0x8) ? "adc" : "sbc");
874 AddToDisHLIXIY(d);
875 AddToDis(d, ",");
876 AddToDisReg16(d, EDop >> 4);
877 return TRUE;
878
879 case 3:
880 Make16BitNum(d, Address, Get16BitParam(d));
881 AddRefEntry(d, d->lastRefAddr, d->lastPC, DISREF_ADDR);
882 AddToDisTabLD(d, "");
883 if (EDop & 8)
884 {
885 AddToDisReg16(d, EDop >> 4);
886 AddToDis(d, ",");
887 AddToDis(d, "(");
888 AddToDis(d, Address);
889 AddToDis(d, ")");
890 }
891 else
892 {
893 AddToDis(d, "(");
894 AddToDis(d, Address);
895 AddToDis(d, ")");
896 AddToDis(d, ",");
897 AddToDisReg16(d, EDop >> 4);
898 }
899 return TRUE;
900
901 case 4:
902 AddToDisTab(d, "neg"); /* It's a NEG */
903 if (EDop != 0x44)
904 AddToDisUndoc(d); /* But undocumented? */
905 return TRUE;
906
907 case 5:
908 AddToDisTab(d, "ret");
909 AddToDisUndoc(d);
910 MARKBLANKLINE;
911 return TRUE;
912
913 case 6:
914 AddToDisTab(d, "im"); /* Interrupt mode... */
915 AddToDis(d, IMModes[(EDop & 0x18) >> 3] );
916 if ((EDop == 0x4e) || (EDop >= 0x60))
917 AddToDisUndoc(d);
918 return TRUE;
919 }
920
921 return FALSE;
922 }
923
924
DisED80toBF(DISZ80 * d)925 int DisED80toBF(DISZ80 *d)
926 {
927 int op;
928
929 op = d->op;
930
931 if (d->cpuType >= DCPU_Z180)
932 {
933 switch (op)
934 {
935 case 0x83: /* otim */
936 case 0x8b: /* otdm */
937 case 0x93: /* otimr */
938 case 0x9b: /* otdmr */
939 AddToDisTab(d, Z180RepeatOps[(op >> 3) & 3]);
940 AddToDisCommentZ180(d);
941 return TRUE;
942 }
943 }
944
945 if (op >= 0xA0)
946 {
947 if ((op & 7) > 3)
948 return FALSE; /* Don't know this! */
949
950 AddToDisTab(d, RepeatOps[(op & 3)+((op & 0x18) >> 1)] );
951 return TRUE;
952 }
953
954 return FALSE;
955 }
956
957
Dis00to3F(DISZ80 * d)958 void Dis00to3F(DISZ80 *d)
959 {
960 int op;
961
962 op = d->op;
963
964 if (d->cpuType == DCPU_Z80GB)
965 {
966 switch(op)
967 {
968 case 0x08: /* ld (nn),sp */
969 AddToDisTabLD(d, "(");
970 AddToDis16BitAbs(d, FALSE);
971 AddToDis(d, "),sp");
972 AddRefEntry(d, d->lastRefAddr, d->lastPC, DISREF_INDIRECT);
973 return;
974
975 case 0x10:
976 AddToDis(d, "stop");
977 return;
978
979 case 0x22:
980 AddToDisTabLD(d, "(hli),a");
981 return;
982
983 case 0x2a:
984 AddToDisTabLD(d, "a,(hli)");
985 return;
986
987 case 0x32:
988 AddToDisTabLD(d, "(hld),a");
989 return;
990
991 case 0x3a:
992 AddToDisTabLD(d, "a,(hld)");
993 return;
994 }
995 }
996
997 switch (op & 0x0f)
998 {
999 case 0:
1000 case 8:
1001 switch ((op >> 3) & 7)
1002 {
1003 case 0: /* 0x00 */
1004 AddToDisTab(d, "nop");
1005 return;
1006
1007 case 1: /* 0x08 */
1008 AddToDisTab(d, "ex");
1009 AddToDis(d, "af,af'");
1010 return;
1011
1012 case 2: /* 0x10 */
1013 AddToDisTab(d, "djnz");
1014 FlagFn(d, AddToDisRel8(d, FALSE));
1015 return;
1016
1017 case 3: /* 0x18 */
1018 AddToDisTab(d, "jr");
1019 FlagFn(d, AddToDisRel8(d, FALSE));
1020 return;
1021
1022 default:
1023 AddToDisTab(d, "jr");
1024 AddToDis(d, Conditions[(op >> 3) & 3] );
1025 FlagFn(d, AddToDisRel8(d, TRUE));
1026 return;
1027 }
1028 case 1:
1029 AddToDisTabLD(d, "");
1030 AddToDisReg16(d, op >> 4);
1031 AddToDis16BitAbs(d, TRUE);
1032 AddRefEntry(d, d->lastRefAddr, d->lastPC, DISREF_ADDR);
1033 return;
1034
1035 case 2:
1036 switch ((op >> 4) & 3)
1037 {
1038 case 0: /* ld (bc),a */
1039 case 1: /* ld (de),a */
1040 AddToDisTabLD(d, "(");
1041 AddToDis(d, Reg16Idx[(op >> 4) & 1] );
1042 AddToDis(d, "),a");
1043 return;
1044
1045 case 2: /* 0x22 = ld (nn),hl */
1046 case 3: /* 0x32 = ld (nn),a */
1047 AddToDisTabLD(d, "(");
1048 AddToDis16BitAbs(d, FALSE);
1049 AddToDis(d, "),");
1050
1051 if (d->realop & 0x10)
1052 {
1053 AddToDis(d, "a");
1054 }
1055 else
1056 {
1057 AddToDisHLIXIY(d);
1058 }
1059
1060 AddRefEntry(d, d->lastRefAddr, d->lastPC, DISREF_INDIRECT);
1061 return;
1062 }
1063
1064 case 3:
1065 AddToDisTab(d, "inc");
1066 AddToDisReg16(d, op>>4);
1067 return;
1068
1069 case 4:
1070 AddToDisTab(d, "inc");
1071 AddToDisReg8(d, op>>3, op>>3);
1072 return;
1073
1074 case 5:
1075 AddToDisTab(d, "dec");
1076 AddToDisReg8(d, op>>3, op>>3);
1077 return;
1078
1079 case 6:
1080 case 0x0e:
1081 AddToDisTabLD(d, "");
1082 AddToDisReg8(d, op>>3, op>>3);
1083 AddToDis8BitAbs(d, TRUE);
1084 return;
1085
1086 case 7:
1087 case 0x0f:
1088 AddToDisTab(d, AccRotType[(op>>3) & 7] );
1089 return;
1090
1091 case 9:
1092 AddToDisTab(d, "add");
1093 AddToDisHLIXIY(d);
1094 AddToDis(d, ",");
1095 AddToDisReg16(d, (op>>4) & 3);
1096 return;
1097
1098 case 0x0a:
1099 switch ((op >> 4) & 3)
1100 {
1101 case 0:
1102 case 1:
1103 AddToDisTabLD(d, "a,(");
1104 AddToDis(d, Reg16Idx[(op >> 4) & 1] );
1105 AddToDis(d, ")");
1106 return;
1107
1108 case 2:
1109 case 3:
1110 if (op & 0x10)
1111 AddToDisTabLD(d, "a");
1112 else
1113 {
1114 AddToDisTabLD(d, "");
1115 AddToDisHLIXIY(d);
1116 }
1117 AddToDis(d, ",(");
1118 AddToDis16BitAbs(d, FALSE);
1119 AddToDis(d, ")");
1120 AddRefEntry(d, d->lastRefAddr, d->lastPC, DISREF_INDIRECT);
1121 return;
1122 }
1123
1124 case 0xb:
1125 AddToDisTab(d, "dec");
1126 AddToDisReg16(d, (op>>4) & 3);
1127 return;
1128
1129
1130 case 0xc:
1131 AddToDisTab(d, "inc");
1132 AddToDisReg8(d, op>>3, op>>3);
1133 return;
1134
1135 case 0xd:
1136 AddToDisTab(d, "dec");
1137 AddToDisReg8(d, op>>3, op>>3);
1138 return;
1139 }
1140
1141 AddToDisUnknown(d, NULL);
1142 return;
1143 }
1144
Dis40to7F(DISZ80 * d)1145 void Dis40to7F(DISZ80 *d)
1146 {
1147 if (d->op == 0x76)
1148 {
1149 AddToDisTab(d, "halt");
1150 return;
1151 }
1152
1153 AddToDisTabLD(d, "");
1154 AddToDisReg8(d, d->realop >> 3, d->realop);
1155 AddToDis(d, ",");
1156 AddToDisReg8(d, d->realop, d->realop >> 3);
1157 return;
1158 }
1159
1160
Dis80toBF(DISZ80 * d)1161 void Dis80toBF(DISZ80 *d)
1162 {
1163 int GenOp;
1164
1165 GenOp = (d->op >> 3) & 7;
1166 AddToDisTab(d, BasicOps[GenOp]);
1167
1168 if (GenOp < 2 || GenOp == 3)
1169 AddToDis(d, "a,");
1170
1171 AddToDisReg8(d, d->op, d->op);
1172 return;
1173 }
1174
1175
DisC0toFF(DISZ80 * d)1176 void DisC0toFF(DISZ80 *d)
1177 {
1178 int GenOp, op;
1179 char port[32], buf[128], num[16], num2[16];
1180 signed char offset;
1181 WORD addr;
1182
1183 op = d->op;
1184
1185 if (d->cpuType == DCPU_Z80GB)
1186 {
1187 switch(op)
1188 {
1189 case 0xd3:
1190 case 0xdb:
1191 case 0xe3:
1192 case 0xe4:
1193 case 0xeb:
1194 case 0xec:
1195 case 0xf2:
1196 case 0xf4:
1197 case 0xfc:
1198 AddToDisUndocNop(d);
1199 return;
1200
1201 case 0xd9:
1202 AddToDis(d, "reti");
1203 return;
1204
1205 case 0xe0: /* ld ($ff00+n),a */
1206 case 0xf0: /* ld a,($ff00+n) */
1207 addr = 0xff00 + GetNextOpCode(d);
1208 Make16BitNum(d, num, 0xff00);
1209 Make8BitNum(d, num2, addr & 0xff);
1210
1211 AddToDisTabLD(d,"");
1212 if (op == 0xe0)
1213 sprintf(buf, "(%s+%s),a", num, num2);
1214 else
1215 sprintf(buf, "a,(%s+%s)", num, num2);
1216 AddToDis(d, buf);
1217 AddRefEntry(d, addr, d->lastPC, DISREF_INDIRECT);
1218 return;
1219
1220 case 0xe2: /* ld ($ff00+c),a */
1221 AddToDisTabLD(d, "");
1222 Make16BitNum(d, num, 0xff00);
1223 sprintf(buf, "(%s+c),a", num);
1224 AddToDis(d, buf);
1225 return;
1226
1227 case 0xe8: /* add sp,nn */
1228 AddToDisTab(d, "add");
1229 AddToDis(d, "sp");
1230 AddToDis16BitAbs(d, TRUE);
1231 return;
1232
1233 case 0xea:
1234 addr = Get16BitParam(d);
1235 Make16BitNum(d, num, addr);
1236 sprintf(buf, "(%s),a", num);
1237 AddToDisTabLD(d, buf);
1238 AddRefEntry(d, addr, d->lastPC, DISREF_INDIRECT);
1239 return;
1240
1241 case 0xf8:
1242 offset = GetNextOpCode(d);
1243 AddToDisTab(d, "ldhl");
1244 AddToDis(d, "sp,");
1245 if (offset >= 0)
1246 {
1247 Make8BitNum(d, num, offset);
1248 sprintf(buf, "%s", num);
1249 }
1250 else
1251 {
1252 Make8BitNum(d, num, -offset);
1253 sprintf(buf, "-%s", num);
1254 }
1255 AddToDis(d, buf);
1256 return;
1257
1258 case 0xfa:
1259 addr = Get16BitParam(d);
1260 Make16BitNum(d, num, addr);
1261 sprintf(buf, "a,(%s)", num);
1262 AddToDisTabLD(d, buf);
1263 AddRefEntry(d, addr, d->lastPC, DISREF_INDIRECT);
1264 return;
1265 }
1266 }
1267
1268 GenOp = (d->op >> 3) & 7;
1269
1270 switch (op & 0xf) /* Break it down into eight basics */
1271 {
1272 case 0:
1273 case 8:
1274 AddToDisTab(d, "ret");
1275 AddToDis(d, Conditions[GenOp]);
1276 MARKBLANKLINE;
1277 return;
1278
1279 case 1: /* POP rr */
1280 case 5: /* PUSH rr */
1281 AddToDisTab(d, (op & 4) ? "push" : "pop");
1282 AddToDisReg16NoAnd(d, ((op >> 4) & 3) + (op >= 0xf0));
1283 return;
1284
1285 case 2:
1286 case 0x0a:
1287 AddToDisTab(d, "jp");
1288 AddToDis(d, Conditions[GenOp]);
1289 FlagFn(d, AddToDis16BitAbs(d, TRUE));
1290 return;
1291
1292 case 4:
1293 case 0x0c:
1294 AddToDisTab(d, "call");
1295 AddToDis(d, Conditions[GenOp]);
1296 FlagFn(d, AddToDis16BitAbs(d, TRUE));
1297 return;
1298
1299 case 3:
1300 switch ((op >> 4) & 3)
1301 {
1302 case 0: /* 0xc3 */
1303 AddToDisTab(d, "jp");
1304 FlagFn(d, AddToDis16BitAbs(d, FALSE));
1305 return;
1306
1307 case 1: /* 0xd3 */
1308 AddToDisTab(d, "out");
1309 Make8BitNum(d, port, GetNextOpCode(d));
1310 sprintf(buf, "(%s),a", port);
1311 AddToDis(d, buf);
1312 AddRefEntry(d, d->op, d->lastPC, DISREF_OUTPORT);
1313 return;
1314
1315 case 2: /* 0xe3 */
1316 AddToDisTab(d, "ex");
1317 AddToDis(d, "(sp),");
1318 AddToDisHLIXIY(d);
1319 return;
1320
1321 case 3: /* 0xf3 */
1322 AddToDisTab(d, "di");
1323 return;
1324 }
1325
1326 case 6:
1327 case 0x0e:
1328 AddToDisTab(d, BasicOps[GenOp] );
1329 if (GenOp < 2 || GenOp == 3)
1330 AddToDis(d, "a,");
1331 AddToDis8BitAbs(d, FALSE);
1332 return;
1333
1334 case 7:
1335 case 0x0f:
1336 AddToDisTab(d, "rst");
1337 Add8BitNum(d, op & (7 << 3));
1338 return;
1339
1340 case 9:
1341 switch ((op >> 4) & 3)
1342 {
1343 case 0: /* 0xc9 */
1344 AddToDisTab(d, "ret");
1345 MARKBLANKLINE;
1346 return;
1347
1348 case 1: /* 0xd9 */
1349 AddToDisTab(d, "exx");
1350 return;
1351
1352 case 2: /* 0xe9 */
1353 AddToDisTab(d, "jp");
1354 AddToDis(d, "(");
1355 AddToDisHLIXIY(d);
1356 AddToDis(d, ")");
1357 return;
1358
1359 case 3: /* 0xf9 */
1360 AddToDisTabLD(d, "sp,");
1361 AddToDisHLIXIY(d);
1362 return;
1363 }
1364
1365
1366 case 0x0b:
1367 switch ((op >> 4) & 3)
1368 {
1369 case 1: /* 0xdb */
1370 AddToDisTab(d, "in");
1371 Make8BitNum(d, port, GetNextOpCode(d));
1372 sprintf(buf,"a,(%s)", port);
1373 AddToDis(d, buf);
1374 AddRefEntry(d, d->op, d->lastPC, DISREF_INPORT);
1375 return;
1376
1377 case 2: /* 0xeb */
1378 AddToDisTab(d, "ex");
1379 AddToDis(d, "de,hl");
1380 return;
1381
1382 case 3: /* 0xfb */
1383 AddToDisTab(d, "ei");
1384 return;
1385 }
1386
1387
1388
1389 case 0x0d: /* N.B. this can only get here with #cd */
1390 AddToDisTab(d, "call");
1391 FlagFn(d, AddToDis16BitAbs(d, FALSE));
1392 return;
1393 }
1394
1395 AddToDisUnknown(d, NULL);
1396 }
1397
1398
AddToDis(DISZ80 * d,char * str)1399 void AddToDis(DISZ80 *d, char *str)
1400 {
1401 char c, *p;
1402 unsigned int i;
1403
1404 if (d->currentPass == DPASS_WRITE)
1405 {
1406 p = d->disBuf;
1407 i = d->disBufIndex;
1408 assert(i < sizeof(d->disBuf));
1409
1410 while ((c = *str++))
1411 p[i++] = c;
1412
1413 p[i] = 0;
1414
1415 assert(i < sizeof(d->disBuf));
1416 d->disBufIndex = i;
1417 }
1418
1419 return;
1420 }
1421
AddToDisTab(DISZ80 * d,char * str)1422 void AddToDisTab(DISZ80 *d, char *str)
1423 {
1424 int l;
1425 char buf[64];
1426
1427 if (d->currentPass == DPASS_WRITE)
1428 {
1429 AddToDis(d, str);
1430
1431 if (d->haveTabbed == FALSE)
1432 {
1433 l = strlen(d->disBuf);
1434 memset(buf, ' ', TABSIZE - l);
1435 buf[TABSIZE - l] = 0;
1436 AddToDis(d, buf);
1437
1438 d->haveTabbed = TRUE;
1439 }
1440 }
1441
1442 return;
1443 }
1444
AddToDisTabDB(DISZ80 * d)1445 void AddToDisTabDB(DISZ80 *d)
1446 {
1447 AddToDisTab(d, (d->layoutDefineByte == NULL) ? "db" : d->layoutDefineByte);
1448 return;
1449 }
1450
1451
AddToDisTabLD(DISZ80 * d,char * str)1452 void AddToDisTabLD(DISZ80 *d, char *str)
1453 {
1454 AddToDisTab(d, "ld");
1455 AddToDis(d, str);
1456 return;
1457 }
1458
1459
AddToDisCommentZ180(DISZ80 * d)1460 void AddToDisCommentZ180(DISZ80 *d)
1461 {
1462 AddToDisComment(d, "Z180 instruction");
1463 return;
1464 }
1465
AddToDisComment(DISZ80 * d,char * str)1466 void AddToDisComment(DISZ80 *d, char *str)
1467 {
1468 if (d->currentPass == DPASS_WRITE)
1469 {
1470 if (!(d->Z80Flags & Z80COMMENT))
1471 {
1472 strcpy(d->commentBuf, d->layoutComment);
1473 d->Z80Flags |= Z80COMMENT;
1474 }
1475
1476 assert((strlen(d->commentBuf) + strlen(str)) < sizeof(d->commentBuf));
1477
1478 strcat(d->commentBuf, str);
1479 }
1480
1481 return;
1482 }
1483
AddToDisHLIXIY(DISZ80 * d)1484 void AddToDisHLIXIY(DISZ80 *d)
1485 {
1486 if (d->Z80Flags & Z80IXIY)
1487 {
1488 AddToDis(d, (d->Z80Flags & Z80IX) ? "ix" : "iy");
1489 }
1490 else
1491 {
1492 AddToDis(d, "hl");
1493 }
1494
1495 return;
1496 }
1497
1498
1499 /* AddToDisReg8(opcode)
1500
1501 Adds b,c,d,e,h,l,(hl) or a to disassembly, taking into consideration
1502 the IX and IY prefixes. "op2" is used to determine whether a "IXl"
1503 reference is valid or not.
1504 */
1505
AddToDisReg8(DISZ80 * d,int op,int op2)1506 void AddToDisReg8(DISZ80 *d, int op, int op2)
1507 {
1508 char num[16];
1509 char buf[64];
1510
1511 op &= 7;
1512
1513 if (d->Z80Flags & Z80IXIY)
1514 {
1515 op2 &= 7;
1516
1517 if (!(op & (Z80CB | Z80ED)) && (op2 != REG_HL) )
1518 {
1519 if (op == REG_L)
1520 {
1521 AddToDis(d, (d->Z80Flags & Z80IX) ? "ixl" : "iyl");
1522 return;
1523 }
1524
1525 if (op == REG_H)
1526 {
1527 AddToDis(d, (d->Z80Flags & Z80IX) ? "ixh" : "iyh");
1528 return;
1529 }
1530 }
1531
1532 if (op == REG_HL)
1533 {
1534 GetIXIYDisplacement(d);
1535
1536 if (d->IXIYDisp >= 0)
1537 {
1538 Make8BitNum(d, num, d->IXIYDisp);
1539 sprintf(buf, "(%s+%s)", ((d->Z80Flags & Z80IX) ? "ix" : "iy"), num);
1540 }
1541 else
1542 {
1543 Make8BitNum(d, num, -d->IXIYDisp);
1544 sprintf(buf, "(%s-%s)", ((d->Z80Flags & Z80IX) ? "ix" : "iy"), num);
1545 }
1546
1547 AddToDis(d, buf);
1548 return;
1549 }
1550 }
1551
1552 AddToDis(d, Reg8Idx[op]);
1553 return;
1554 }
1555
1556
1557 /* AddToDisReg16(opcode)
1558
1559 Adds bc,de,hl or sp to disassembly, taking into consideration
1560 the IX and IY prefixes
1561 */
1562
AddToDisReg16(DISZ80 * d,int op)1563 void AddToDisReg16(DISZ80 *d, int op)
1564 {
1565 op &= 3;
1566 if ( (op == 2) && (d->Z80Flags & Z80IXIY) )
1567 AddToDisHLIXIY(d);
1568 else
1569 AddToDis(d, Reg16Idx[op]);
1570 return;
1571 }
1572
AddToDisReg16NoAnd(DISZ80 * d,int op)1573 void AddToDisReg16NoAnd(DISZ80 *d, int op)
1574 {
1575 if ( (op == 2) && (d->Z80Flags & Z80IXIY) )
1576 AddToDisHLIXIY(d);
1577 else
1578 AddToDis(d, Reg16Idx[op]);
1579 return;
1580 }
1581
1582
AddToDisRel8(DISZ80 * d,int CommaFlag)1583 WORD AddToDisRel8(DISZ80 *d, int CommaFlag)
1584 {
1585 char buf[64], num[16];
1586 signed char o;
1587
1588 if (CommaFlag)
1589 AddToDis(d, ",");
1590
1591 o = (char)GetNextOpCode(d);
1592
1593 d->lastRefAddr = (WORD)(d->PC + o);
1594 Add16BitAddress(d, d->lastRefAddr);
1595
1596 if (d->flags & DISFLAG_RELCOMMENT)
1597 {
1598 Make8BitNum(d, num, (o >= 0) ? o : -o);
1599 sprintf(buf, "(%s%s)", (o >= 0) ? "+" : "-", num);
1600 AddToDisComment(d, buf);
1601 }
1602
1603 return d->lastRefAddr;
1604 }
1605
AddToDis8BitAbs(DISZ80 * d,int CommaFlag)1606 void AddToDis8BitAbs(DISZ80 *d, int CommaFlag)
1607 {
1608 if (CommaFlag)
1609 AddToDis(d, ",");
1610
1611 GetNextOpCode(d);
1612 Add8BitNum(d, d->op);
1613 return;
1614 }
1615
AddToDis16BitAbs(DISZ80 * d,int CommaFlag)1616 WORD AddToDis16BitAbs(DISZ80 *d, int CommaFlag)
1617 {
1618 if (CommaFlag)
1619 AddToDis(d, ",");
1620
1621 Get16BitParam(d);
1622 Add16BitAddress(d, d->lastRefAddr);
1623 return d->lastRefAddr;
1624 }
1625
AddToDisUndoc(DISZ80 * d)1626 void AddToDisUndoc(DISZ80 *d)
1627 {
1628 AddToDisComment(d, "Undocumented");
1629 return;
1630 }
1631
AddToDisUndocNop(DISZ80 * d)1632 void AddToDisUndocNop(DISZ80 *d)
1633 {
1634 AddToDis(d, "nop");
1635 AddToDisComment(d, "Undocumented");
1636 return;
1637 }
1638
1639
1640
1641 /*
1642 void AddToDisUnknown(char *Comment)
1643
1644 Handles the dumping of an unknown opcode sequence
1645 */
1646
AddToDisUnknown(DISZ80 * d,char * Comment)1647 void AddToDisUnknown(DISZ80 *d, char *Comment)
1648 {
1649 int i, numOpCodes;
1650 char buf[64];
1651
1652 if (d->currentPass != DPASS_WRITE)
1653 return;
1654
1655 AddToDisTabDB(d);
1656
1657 numOpCodes = abs(d->PC - d->lastPC);
1658 d->PC = d->lastPC;
1659
1660 /* We're going to rewind back to the start of the bad opcode, so clear the hex stream dump */
1661 d->hexDisBuf[0] = 0;
1662
1663 for (i = 0; i < numOpCodes; i++)
1664 {
1665 Make8BitNum(d, buf, GetNextOpCode(d));
1666 if (i < (numOpCodes-1))
1667 strcat(buf, ", ");
1668 AddToDis(d, buf);
1669 }
1670
1671 if (Comment == NULL)
1672 AddToDisComment(d, "Unknown opcode");
1673 else
1674 AddToDisComment(d, Comment);
1675
1676 return;
1677 }
1678
1679
GetIXIYDisplacement(DISZ80 * d)1680 char GetIXIYDisplacement(DISZ80 *d)
1681 {
1682 if (!(d->Z80Flags & Z80GOTIXIYDISP)) /* Already got IXIY displacement? */
1683 {
1684 d->IXIYDisp = (char)GetNextOpCode(d);
1685 d->Z80Flags |= Z80GOTIXIYDISP;
1686 }
1687
1688 return d->IXIYDisp;
1689 }
1690
1691
Get16BitParam(DISZ80 * d)1692 WORD Get16BitParam(DISZ80 *d)
1693 {
1694 d->lastRefAddr = (WORD)GetNextOpCode(d);
1695 d->lastRefAddr |= (GetNextOpCode(d) << 8);
1696 return d->lastRefAddr;
1697 }
1698
1699
FlagFn(DISZ80 * d,unsigned int Addr)1700 void FlagFn(DISZ80 *d, unsigned int Addr)
1701 {
1702 if (d->labelledOutput == FALSE || d->currentPass != DPASS_ANALYSE)
1703 return;
1704
1705 assert(d->fnMap != NULL);
1706 assert(Addr < Z80MEMSIZE);
1707 d->fnMap[Addr] = TRUE;
1708 return;
1709 }
1710
1711
IsFnUsed(DISZ80 * d,unsigned int Addr)1712 int IsFnUsed(DISZ80 *d, unsigned int Addr)
1713 {
1714 assert(Addr < Z80MEMSIZE);
1715
1716 if (d->fnMap != NULL)
1717 return (d->fnMap[Addr]);
1718
1719 return 0;
1720 }
1721
1722
1723
AllocateMap(DISZ80 * d,char * errorStr,unsigned int bytesWanted)1724 BYTE* AllocateMap(DISZ80 *d, char *errorStr, unsigned int bytesWanted)
1725 {
1726 BYTE *pMap;
1727
1728 pMap = (BYTE *)malloc(bytesWanted);
1729
1730 if (pMap == NULL)
1731 dZ80_Error(d, errorStr);
1732 else
1733 memset(pMap, 0, bytesWanted);
1734
1735 return pMap;
1736 }
1737
1738
1739 /* Create the output .asm file and header */
CreateOutputASMFile(DISZ80 * d)1740 int CreateOutputASMFile(DISZ80 *d)
1741 {
1742 char MsgBuf[_MAX_PATH + 80];
1743 char buf[256];
1744 time_t secs_now;
1745 struct tm *time_now;
1746
1747 /* Set up the time structures */
1748 time(&secs_now);
1749 time_now = localtime(&secs_now);
1750
1751 if (d->outFileName[0])
1752 {
1753 d->outStream = fopen(d->outFileName, "wt");
1754
1755 if (d->outStream == NULL)
1756 {
1757 sprintf(buf, "Couldn't create the output file %s\n", d->outFileName);
1758 dZ80_Error(d, buf);
1759 DisZ80CleanUp(d);
1760 return DERR_COULDNTCREATEFILE;
1761 }
1762
1763 sprintf(MsgBuf, "%sDisassembly of the file \"%s\"\n%s\n", d->layoutComment, d->srcFileName, d->layoutComment);
1764 fwrite(MsgBuf, strlen(MsgBuf), 1, d->outStream);
1765
1766 sprintf(MsgBuf, "%sCPU Type: %s\n%s\n", d->layoutComment, dZ80CpuTypeNames[d->cpuType], d->layoutComment);
1767 fwrite(MsgBuf, strlen(MsgBuf), 1, d->outStream);
1768
1769 if (d->opMapFileName[0])
1770 {
1771 sprintf(MsgBuf, "%sUsing the opcode map file \"%s\"\n%s", d->layoutComment, d->opMapFileName, d->layoutComment);
1772 fwrite(MsgBuf, strlen(MsgBuf), 1, d->outStream);
1773 }
1774
1775 sprintf(MsgBuf, "%sCreated with dZ80 %s\n%s", d->layoutComment, VersionString, d->layoutComment);
1776 fwrite(MsgBuf, strlen(MsgBuf), 1, d->outStream);
1777
1778 if (d->scriptFileName[0])
1779 {
1780 sprintf(MsgBuf, " using script \"%s\"\n%s", d->scriptFileName, d->layoutComment);
1781 fwrite(MsgBuf, strlen(MsgBuf), 1, d->outStream);
1782 }
1783
1784 sprintf(MsgBuf, "\n%s", d->layoutComment);
1785 fwrite(MsgBuf, strlen(MsgBuf), 1, d->outStream);
1786
1787 strftime(MsgBuf, sizeof(MsgBuf), "on %A, %d of %B %Y at %I:%M %p", time_now);
1788 fwrite(MsgBuf, strlen(MsgBuf), 1, d->outStream);
1789
1790 sprintf(MsgBuf, "\n%s\n", d->layoutComment);
1791 fwrite(MsgBuf, strlen(MsgBuf), 1, d->outStream);
1792
1793 if (d->labelledOutput)
1794 {
1795 PrepareDisInstruction(d);
1796 AddToDisTab(d, "org");
1797 Make16BitNum(d, MsgBuf, d->disStart);
1798 strcat(MsgBuf,"\n");
1799 AddToDis(d, MsgBuf);
1800 WriteDisLine(d, d->lastPC);
1801 }
1802 }
1803
1804 return DERR_NONE;
1805 }
1806
1807
1808 /*
1809 PrepareOpMap()
1810
1811 This was changed for dZ80 2.0 so that the opcode map is always allocated and initialised with
1812 all bits set to "code". This was to allow for the script to manipulate the opMap regardless of
1813 whether one had been loaded.
1814 */
1815
dZ80_AllocateOpMap(DISZ80 * d)1816 int dZ80_AllocateOpMap(DISZ80 *d)
1817 {
1818 if (d->opMap == NULL)
1819 {
1820 if ((d->opMap = AllocateMap(d, "Couldn't allocate memory for the opcode map.", Z80MEMSIZE/8)) == NULL)
1821 {
1822 DisZ80CleanUp(d);
1823 return DERR_OUTOFMEM;
1824 }
1825
1826 /* Set all the bits to "code" */
1827 memset(d->opMap, 0xff, Z80MEMSIZE / 8);
1828 }
1829
1830 return DERR_NONE;
1831 }
1832
1833
PrepareOpMap(DISZ80 * d)1834 int PrepareOpMap(DISZ80 *d)
1835 {
1836 char buf[256];
1837 int err;
1838 FILE *opStream;
1839
1840 err = dZ80_AllocateOpMap(d);
1841 if (err)
1842 return err;
1843
1844 if (d->opMapFileName[0])
1845 {
1846 opStream = fopen(d->opMapFileName, "rb");
1847
1848 if (opStream == NULL)
1849 {
1850 sprintf(buf, "Couldn't open the opcode map file \"%s\"", d->opMapFileName);
1851 dZ80_Error(d, buf);
1852 DisZ80CleanUp(d);
1853 return DERR_COULDNTOPENFILE;
1854 }
1855
1856 if (fread(d->opMap, 1, Z80MEMSIZE / 8, opStream) < (Z80MEMSIZE / 8) )
1857 dZ80_ShowMsg(d, "Warning: Couldn't read the entire opcode map file");
1858
1859 fclose(opStream);
1860 }
1861
1862 return DERR_NONE;
1863 }
1864
1865
1866
WriteReferenceFile(DISZ80 * d)1867 void WriteReferenceFile(DISZ80 *d)
1868 {
1869 unsigned int t, n;
1870 char buf[80 + _MAX_PATH];
1871 char *TypeMsg;
1872 char num1[32], num2[32];
1873 DISREF *p;
1874 DISREFADDR *ra;
1875 DISZ80 qd;
1876 FILE *refStream;
1877
1878 if (!(d->flags & DISFLAG_ANYREF))
1879 return;
1880
1881 if (d->refFileName[0] == 0)
1882 {
1883 dZ80_Error(d, "Missing reference filename.");
1884 return;
1885 }
1886
1887 if (!(d->flags & DISFLAG_QUIET))
1888 {
1889 sprintf(buf, "Writing reference file: %s", d->refFileName);
1890 dZ80_ShowMsg(d, buf);
1891 }
1892
1893 refStream = fopen(d->refFileName, "wt");
1894 if (refStream == NULL)
1895 {
1896 sprintf(buf, "Couldn't create the reference file \"%s\".", d->refFileName);
1897 dZ80_Error(d, buf);
1898 return;
1899 }
1900
1901 sprintf(buf,"dZ80 %s Reference file from the disassembly of \"%s\".\n\n", VersionString, d->srcFileName);
1902 fwrite(buf, 1, strlen(buf), refStream);
1903
1904 for(t = 0; t < DISREF_TOTAL; t++)
1905 {
1906 switch(t)
1907 {
1908 case DISREF_INPORT:
1909 TypeMsg = "Input Port";
1910 break;
1911
1912 case DISREF_OUTPORT:
1913 TypeMsg = "Output Port";
1914 break;
1915
1916 case DISREF_ADDR:
1917 TypeMsg = "Direct address";
1918 break;
1919
1920 case DISREF_INDIRECT:
1921 TypeMsg = "Indirect address";
1922 break;
1923
1924 default:
1925 assert(FALSE);
1926 TypeMsg = "wah?";
1927 break;
1928 }
1929
1930 n = d->numRefs[t];
1931 if (n)
1932 {
1933 sprintf(buf, "%s Reference (%d entries)\n", TypeMsg, n);
1934 fwrite(buf, 1, strlen(buf), refStream);
1935 UnderlineText(refStream, buf);
1936
1937 p = d->pRefHead[t];
1938 while(p != NULL)
1939 {
1940 Make16BitNum(d, num1, p->Addr);
1941 sprintf(buf, "%s %s. %u references:\n", TypeMsg, num1, p->Hits);
1942 fwrite(buf, 1, strlen(buf), refStream);
1943 UnderlineText(refStream, buf);
1944
1945 ra = p->pRefAddrHead;
1946 while (ra != NULL)
1947 {
1948 memset(&qd, 0, sizeof(qd));
1949 qd.mem0Start = d->mem0Start;
1950 qd.memCB = d->memCB;
1951 qd.start = qd.end = ra->RefAddress;
1952 qd.flags = d->flags | DISFLAG_SINGLE;
1953 qd.cpuType = d->cpuType;
1954 dZ80_InheritRadix(&qd, d);
1955
1956 dZ80_Disassemble(&qd);
1957
1958 Make16BitNum(d, num2, ra->RefAddress);
1959 sprintf(buf, "%8s: %s\n", num2, qd.disBuf);
1960 fwrite(buf, 1, strlen(buf), refStream);
1961
1962 ra = ra->pNext;
1963 }
1964
1965 sprintf(buf, "\n");
1966 fwrite(buf, 1, strlen(buf), refStream);
1967 p = p->pNext;
1968 }
1969
1970 sprintf(buf, "\n");
1971 fwrite(buf, 1, strlen(buf), refStream);
1972 }
1973 }
1974
1975 sprintf(buf, "End of reference file for \"%s\"\n\n", d->srcFileName);
1976 fwrite(buf, 1, strlen(buf), refStream);
1977
1978 fclose(refStream);
1979 d->createdRefOK = TRUE;
1980 return;
1981 }
1982
1983
UnderlineText(FILE * stream,char * text)1984 void UnderlineText(FILE *stream, char *text)
1985 {
1986 int l;
1987 char buf[256];
1988
1989 l = strlen(text) - 1;
1990 memset(buf, '-', l);
1991 buf[l] = 0;
1992 strcat(buf, "\n\n");
1993 fwrite(buf, 1, strlen(buf), stream);
1994 return;
1995 }
1996
1997
AddRefEntry(DISZ80 * d,int Addr,int PC,int refType)1998 void AddRefEntry(DISZ80 *d, int Addr, int PC, int refType)
1999 {
2000 DISREF *p, *pIns, *pPrev;
2001
2002 /* Don't add reference entries if we're scanning for functions */
2003 if ((d->currentPass != DPASS_WRITE) || (!(d->flags & DISFLAG_ANYREF)))
2004 return;
2005
2006 switch (refType)
2007 {
2008 case DISREF_INPORT:
2009 if (!(d->flags & DISFLAG_REFINPORT))
2010 return;
2011 break;
2012
2013 case DISREF_OUTPORT:
2014 if (!(d->flags & DISFLAG_REFOUTPORT))
2015 return;
2016 break;
2017
2018 case DISREF_ADDR:
2019 case DISREF_INDIRECT:
2020 if (d->flags & DISFLAG_REFLIMITRANGE)
2021 {
2022 if (Addr >= d->disStart && Addr <= d->disEnd)
2023 return;
2024 }
2025
2026 if ((refType == DISREF_ADDR) && !(d->flags & DISFLAG_REFADDR))
2027 return;
2028
2029 if ((refType == DISREF_INDIRECT) && !(d->flags & DISFLAG_REFINDIRECT))
2030 return;
2031
2032 break;
2033
2034 default:
2035 assert(FALSE);
2036 return;
2037 }
2038
2039 /*
2040 Locate the insertion point of this new entry, or if
2041 there's already an existing one (same address), use that
2042 */
2043 pIns = d->pRefHead[refType];
2044 pPrev = NULL;
2045
2046 while (pIns != NULL)
2047 {
2048 if (pIns->Addr == Addr)
2049 {
2050 AddReferenceAddr(d, pIns, PC);
2051 return;
2052 }
2053
2054 if (pIns->Addr > Addr)
2055 break;
2056
2057 pPrev = pIns;
2058 pIns = pIns->pNext;
2059 }
2060
2061
2062 /* We have a brand new entry (either at the head or tail of the list, or needs to be crow-barred in :) */
2063 p = malloc(sizeof(DISREF));
2064 if (p == NULL)
2065 return;
2066
2067 memset(p, 0, sizeof(DISREF));
2068
2069 /* First entry for this reference type? */
2070
2071 if (pPrev != NULL)
2072 {
2073 p->pPrev = pPrev;
2074 pPrev->pNext = p;
2075 }
2076 else
2077 {
2078 d->pRefHead[refType] = p;
2079 }
2080
2081 if (pIns != NULL)
2082 {
2083 p->pNext = pIns;
2084 pIns->pPrev = p;
2085 }
2086
2087
2088 #if 0
2089 p->pPrev = pPrev; /* Link to previous entry (if any) */
2090 p->pNext = pIns; /* Link the next to the..erm..next */
2091
2092 if (pPrev != NULL)
2093 pPrev->pNext = p; /* Link the following entry to this one (barge in) */
2094
2095 if (d->pRefHead[refType] == NULL)
2096 d->pRefHead[refType] = p; /* Must be the first in the list */
2097
2098 if (pIns != NULL)
2099 pIns->pPrev = p; /* Link the following entry to me */
2100 #endif
2101
2102 p->RefType = refType;
2103 p->Addr = (WORD)Addr;
2104 p->Hits = 0;
2105
2106 AddReferenceAddr(d, p, PC);
2107 return;
2108 }
2109
2110
AddReferenceAddr(DISZ80 * d,DISREF * p,int PC)2111 void AddReferenceAddr(DISZ80 *d, DISREF *p, int PC)
2112 {
2113 DISREFADDR *n, *t;
2114
2115
2116 n = malloc(sizeof(DISREFADDR));
2117 if (n == NULL)
2118 return;
2119
2120 memset(n, 0, sizeof(DISREFADDR));
2121
2122 t = p->pRefAddrTail;
2123
2124 if (t == NULL)
2125 {
2126 p->pRefAddrHead = p->pRefAddrTail = n;
2127 }
2128 else
2129 {
2130 assert(t->RefAddress < PC);
2131 t->pNext = n;
2132 p->pRefAddrTail = n;
2133 }
2134
2135 n->RefAddress = (WORD)PC;
2136 p->Hits++;
2137
2138 d->numRefs[p->RefType]++;
2139 return;
2140 }
2141
2142
DoProgress(DISZ80 * d,int forceUpdate)2143 void DoProgress(DISZ80 *d, int forceUpdate)
2144 {
2145 if (!(d->flags & DISFLAG_QUIET))
2146 {
2147 if (d->fnProgressCallback != NULL)
2148 {
2149 d->progressCounter--;
2150 if ((forceUpdate) || d->progressCounter <= 0)
2151 {
2152 d->fnProgressCallback(d);
2153 d->progressCounter = PROGRESSUPDATEFREQ;
2154 }
2155 }
2156 }
2157
2158 return;
2159 }
2160
2161
Add16BitAddress(DISZ80 * d,WORD Addr)2162 void Add16BitAddress(DISZ80 *d, WORD Addr)
2163 {
2164 char buf[32];
2165
2166 if ((d->labelledOutput == TRUE) && (d->currentPass == DPASS_WRITE) && (d->flags & DISFLAG_USELABELADDRS))
2167 {
2168 if (IsFnUsed(d, Addr))
2169 {
2170 sprintf(buf, "l%04x", Addr);
2171 AddToDis(d, buf);
2172 return;
2173 }
2174 }
2175
2176 Add16BitNum(d, Addr);
2177 return;
2178 }
2179
2180
Add8BitNum(DISZ80 * d,int Num)2181 void Add8BitNum(DISZ80 *d, int Num)
2182 {
2183 char buf[32];
2184
2185 Make8BitNum(d, buf, Num);
2186 AddToDis(d, buf);
2187 return;
2188 }
2189
2190
Make8BitNum(DISZ80 * d,char * Dst,int Num)2191 void Make8BitNum(DISZ80 *d, char *Dst, int Num)
2192 {
2193 char num[16];
2194
2195 switch(d->layoutRadix)
2196 {
2197 case DRADIX_OCTAL:
2198 sprintf(num, "%o", Num);
2199 break;
2200
2201 case DRADIX_DECIMAL:
2202 sprintf(num, "%d", Num);
2203 break;
2204
2205 case DRADIX_HEX:
2206 sprintf(num, "%02x", Num);
2207 break;
2208
2209 default:
2210 num[0] = '\0';
2211 break;
2212 }
2213
2214 /* Added in 2.0 - "{" is a special case that adds a "0" only if the first digit
2215 is non-numeric
2216 */
2217
2218 if (d->layoutNumberPrefix[0] == '{')
2219 sprintf(Dst, "%s%s%s", (num[0] <'0' || num[0] > '9') ? "0" : "", num, d->layoutNumberSuffix);
2220 else
2221 sprintf(Dst, "%s%s%s", d->layoutNumberPrefix, num, d->layoutNumberSuffix);
2222
2223 return;
2224 }
2225
Add16BitNum(DISZ80 * d,int Num)2226 void Add16BitNum(DISZ80 *d, int Num)
2227 {
2228 char buf[32];
2229
2230 Make16BitNum(d, buf, Num);
2231 AddToDis(d, buf);
2232 return;
2233 }
2234
Make16BitNum(DISZ80 * d,char * Dst,int Num)2235 void Make16BitNum(DISZ80 *d, char *Dst, int Num)
2236 {
2237 char num[8];
2238
2239 switch(d->layoutRadix)
2240 {
2241 case DRADIX_OCTAL:
2242 sprintf(num, "%o", Num);
2243 break;
2244
2245 case DRADIX_DECIMAL:
2246 sprintf(num, "%d", Num);
2247 break;
2248
2249 case DRADIX_HEX:
2250 sprintf(num, "%04x", Num);
2251 break;
2252
2253 default:
2254 num[0] = '\0';
2255 break;
2256 }
2257
2258 /*
2259 Added in 2.0 - "{" is a special case that adds a "0" only if the first digit
2260 is non-numeric
2261 */
2262
2263 if (d->layoutNumberPrefix[0] == '{')
2264 sprintf(Dst, "%s%s%s", (num[0] <'0' || num[0] > '9') ? "0" : "", num, d->layoutNumberSuffix);
2265 else
2266 sprintf(Dst, "%s%s%s", d->layoutNumberPrefix, num, d->layoutNumberSuffix);
2267
2268 return;
2269 }
2270
MakeLJustified16BitNum(DISZ80 * d,char * dst,int num)2271 void MakeLJustified16BitNum(DISZ80 *d, char *dst, int num)
2272 {
2273 switch(d->layoutRadix)
2274 {
2275 case DRADIX_OCTAL:
2276 sprintf(dst, "%6o", num);
2277 break;
2278
2279 case DRADIX_DECIMAL:
2280 sprintf(dst, "%5d", num);
2281 break;
2282
2283 case DRADIX_HEX:
2284 sprintf(dst, "%04x", num);
2285 break;
2286 }
2287
2288 return;
2289 }
2290
2291
dZ80_StringToLower(char * s)2292 void dZ80_StringToLower(char *s)
2293 {
2294 while (*s) {
2295 *s = (char)tolower(*s);
2296 s++;
2297 }
2298
2299 return;
2300 }
2301
dZ80_StringToUpper(char * s)2302 void dZ80_StringToUpper(char *s)
2303 {
2304 while (*s) {
2305 *s = (char)toupper(*s);
2306 s++;
2307 }
2308
2309 return;
2310 }
2311
dZ80_Error(DISZ80 * d,char * msg)2312 void dZ80_Error(DISZ80 *d, char *msg)
2313 {
2314 if (d->fnErrorMessage != NULL)
2315 d->fnErrorMessage(msg);
2316
2317 return;
2318 }
2319
dZ80_ShowMsg(DISZ80 * d,char * msg)2320 void dZ80_ShowMsg(DISZ80 *d, char *msg)
2321 {
2322 if(d->fnOutputMessage != NULL)
2323 d->fnOutputMessage(msg);
2324
2325 return;
2326 }
2327
dZ80_SafeStringCopy(char * dst,char * src,int dstSize)2328 void dZ80_SafeStringCopy(char *dst, char *src, int dstSize)
2329 {
2330 int l;
2331
2332 l = strlen(src);
2333 if (l < dstSize)
2334 {
2335 strcpy(dst, src);
2336 }
2337 else
2338 {
2339 strncpy(dst, src, dstSize - 1);
2340 dst[dstSize - 1] = 0;
2341 }
2342
2343 return;
2344 }
2345
2346
dZ80_GetErrorText(int errNum)2347 const char *dZ80_GetErrorText(int errNum)
2348 {
2349 if (errNum >= 0 && errNum < DERR_TOTAL)
2350 return dZ80ErrorMsgs[errNum];
2351
2352 return "dZ80_GetErrorText: bad error #";
2353 }
2354
2355
StartPass(DISZ80 * d)2356 void StartPass(DISZ80 *d)
2357 {
2358 d->numInstructions = 0; /* Number of instructions disassembled */
2359 d->haveWrapped = FALSE; /* PC hasn't wrapped around */
2360 d->PC = d->disStart;
2361
2362 /* Clear the disassembly buffer */
2363 PrepareDisInstruction(d);
2364 return;
2365 }
2366
WithinDisRange(DISZ80 * d)2367 int WithinDisRange(DISZ80 *d)
2368 {
2369 return ((d->PC <= d->disEnd) && (!d->haveWrapped));
2370 }
2371
2372