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