/************************************************************************\
 * File Version Information
 * $Header: /Altair32v2/Debug.c 26    11/08/06 9:21p Racini $
 ************************************************************************/
/************************************************************************\
  MITS Altair Emulator
  Processor Debugger

  Modifications for the Altair32 Emulator
  Copyright (c) 2001-2006 Richard A. Cini


Change Log:
  2001/11/13  RAC -- Initial modifications
  2001/12/07  RAC -- Using Di80 macro since that points	to
  						either normal or breakpoint handling.
  2001/12/14  RAC -- RELEASE MARKER -- v2.1
  2002/01/31  RAC -- RELEASE MARKER -- v2.2
  2002/07/07  RAC -- RELEASE MARKER -- v2.3
  2002/08/23  RAC -- RELEASE MARKER -- v2.30.10
  2002/11/15  RAC -- RELEASE MARKER -- v2.40.2100
  2003/04/26  RAC -- RELEASE MARKER -- v2.50.2045
  2004/07/30  RAC -- RELEASE MARKER -- v3.00.0135
  2006/05/12  RAC -- RELEASE MARKER -- v3.10.0200
  2006/11/15  RAC -- RELEASE MARKER -- v3.20.0400
\************************************************************************/
/** Z80: portable Z80 emulator *******************************/
/**                                                         **/
/**                         Debug.c                         **/
/**                                                         **/
/** This file contains the built-in debugging routine for   **/
/** the Z80 emulator which is called on each Z80 step when  **/
/** Trap!=0.                                                **/
/**                                                         **/
/** Copyright (C) Marat Fayzullin 1995,1996,1997            **/
/**     You are not allowed to distribute this software     **/
/**     commercially. Please, notify me, if you make any    **/
/**     changes to this file.                               **/
/*************************************************************/
/* Modified by Jim Battle to support 8080 processors
 * at the expense of Z80 support
 */


#include <windows.h>
#include <stdio.h>		// C-lib
#include <ctype.h>
#include <string.h>
#include "altair32.h"
#include "windbg.h"
#include "windbg_sub.h"
#include "i8080.h"

// for each opcode, the string encodes the following symbols
//    % = print immediate 8b value
//    # = print immediate 16b value
//    / = separates instruction from informational fields
//        #  = print 16b immediate
//        !B = print value of BC
//        !D = print value of DE
//        !H = print value of HL
//        @b = print 8b MEM[BC]
//        @d = print 8b MEM[DE]
//        @h = print 8b MEM[HL]
//        @B = print 16b MEM[BC]
//        @D = print 16b MEM[DE]
//        @H = print 16b MEM[HL]
//        @% = print  8b MEM[immediate 16]
//        @# = print 16b MEM[immediate 16]
static char *Mnemonics8080[256] =
{
  "NOP","LXI B,#h","STAX B/[!B]","INX B","INR B","DCR B","MVI B,*h","RLC",
  "DB 08H","DAD B","LDAX B/[!B]=@b","DCX B","INR C","DCR C","MVI C,*h","RRC",
  "DB 10H","LXI D,#h","STAX D/[!D]","INX D","INR D","DCR D","MVI D,*h","RAL",
  "DB 18H","DAD D","LDAX D/[!D]=@d","DCX D","INR E","DCR E","MVI E,*h","RAR",
  "DB 20H","LXI H,#h","SHLD #h/[!H]","INX H","INR H","DCR H","MVI H,*h","DAA",
  "DB 28H","DAD H","LHLD #h/[!H]=@#","DCX H","INR L","DCR L","MVI L,*h","CMA",
  "DB 30H","LXI SP,#h","STA #h/[#]","INX SP","INR M/[!H]=@h","DCR M/[!H]=@h","MVI M,*h/[!H]","STC",
  "DB 38H","DAD SP","LDA #h/[#]=@%","DCX SP","INR A","DCR A","MVI A,*h","CMC",
  "MOV B,B","MOV B,C","MOV B,D","MOV B,E","MOV B,H","MOV B,L","MOV B,M/[!H]=@h","MOV B,A",
  "MOV C,B","MOV C,C","MOV C,D","MOV C,E","MOV C,H","MOV C,L","MOV C,M/[!H]=@h","MOV C,A",
  "MOV D,B","MOV D,C","MOV D,D","MOV D,E","MOV D,H","MOV D,L","MOV D,M/[!H]=@h","MOV D,A",
  "MOV E,B","MOV E,C","MOV E,D","MOV E,E","MOV E,H","MOV E,L","MOV E,M/[!H]=@h","MOV E,A",
  "MOV H,B","MOV H,C","MOV H,D","MOV H,E","MOV H,H","MOV H,L","MOV H,M/[!H]=@h","MOV H,A",
  "MOV L,B","MOV L,C","MOV L,D","MOV L,E","MOV L,H","MOV L,L","MOV L,M/[!H]=@h","MOV L,A",
  "MOV M,B/[!H]","MOV M,C/[!H]","MOV M,D/[!H]","MOV M,E/[!H]","MOV M,H/[!H]","MOV M,L/[!H]","HLT","MOV M,A/[!H]",
  "MOV A,B","MOV A,C","MOV A,D","MOV A,E","MOV A,H","MOV A,L","MOV A,M/[!H]=@h","MOV A,A",
  "ADD B","ADD C","ADD D","ADD E","ADD H","ADD L","ADD M/[!H]=@h","ADD A",
  "ADC B","ADC C","ADC D","ADC E","ADC H","ADC L","ADC M/[!H]=@h","ADC A",
  "SUB B","SUB C","SUB D","SUB E","SUB H","SUB L","SUB M/[!H]=@h","SUB A",
  "SBB B","SBB C","SBB D","SBB E","SBB H","SBB L","SBB M/[!H]=@h","SBB A",
  "ANA B","ANA C","ANA D","ANA E","ANA H","ANA L","ANA M/[!H]=@h","ANA A",
  "XRA B","XRA C","XRA D","XRA E","XRA H","XRA L","XRA M/[!H]=@h","XRA A",
  "ORA B","ORA C","ORA D","ORA E","ORA H","ORA L","ORA M/[!H]=@h","ORA A",
  "CMP B","CMP C","CMP D","CMP E","CMP H","CMP L","CMP M/[!H]=@h","CMP A",
  "RNZ","POP B","JNZ #h","JMP #h","CNZ #h","PUSH B","ADI *h","RST 0",
  "RZ","RET","JZ #h","DB 0CBH","CZ #h","CALL #h","ACI *h","RST 1",
  "RNC","POP D","JNC #h","OUT *h","CNC #h","PUSH D","SUI *h","RST 2",
  "RC","DB 0D9H","JC #h","IN *h","CC #h","DB 0DDH","SBI *h","RST 3",
  "RPO","POP H","JPO #h","XTHL","CPO #h","PUSH H","ANI *h","RST 4",
  "RPE","PCHL","JPE #h","XCHG","CPE #h","DB 0EDH","XRI *h","RST 5",
  "RP","POP PSW","JP #h","DI","CP #h","PUSH PSW","ORI *h","RST 6",
  "RM","SPHL","JM #h","EI","CM #h","DB 0FDH","CPI *h","RST 7"
};


static int Len8080[256] =
{
  1,3,1,1,1,1,2,1,
  1,1,1,1,1,1,2,1,
  1,3,1,1,1,1,2,1,
  1,1,1,1,1,1,2,1,
  1,3,3,1,1,1,2,1,
  1,1,3,1,1,1,2,1,
  1,3,3,1,1,1,2,1,
  1,1,3,1,1,1,2,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,3,3,3,1,2,1,
  1,1,3,1,3,3,2,1,
  1,1,3,2,3,1,2,1,
  1,1,3,2,3,1,2,1,
  1,1,3,1,3,1,2,1,
  1,1,3,1,3,1,2,1,
  1,1,3,1,3,1,2,1,
  1,1,3,1,3,1,2,1
};


// return the length of the instruction at address A
int OpLen(word adr)
{
    byte op = Di80(adr);
    return Len8080[op];
}


/** DAsm() ***************************************************/
/** DAsm() will disassemble the code at adress A and put    **/
/** the output text into S. It will return the number of    **/
/** bytes disassembled.                                     **/
/*************************************************************/
int DAsm(char *S, word adrs, int extended)
{
    char H[10], ch;
    byte op    = Di80(adrs);
    byte imm8  = Di80((word)(adrs+1));
    word imm16 = 256*Di80((word)(adrs+2)) + imm8;
    char *p1 = Mnemonics8080[op];
    char *p2 = S;
    word addr;
    int done;

    // copy mnemonic
    while ((ch = *p1) && (ch != ' ')) {
        *p2++ = ch;
        p1++;
    }

    // insert spaces after mnemonic to make operands line up
    if (*p1) {
        while (p2-S < 5)
            *p2++ = ' ';
    }

    // copy the rest, expanding wildcards as we go
    done = 0;
    while (!done && (ch = *p1++)) {

        switch (ch) {

        case '*':
            // insert immediate 8b value
            sprintf(H, "%02X", imm8);
            strcpy(p2,H);
            p2+=2;
	    break;

	case '#':
	    // insert immediate 16b value
	    sprintf(H, "%04X", imm16);
	    strcpy(p2,H);
	    p2+=4;
	    break;

	case '/':
	    // separate informational fields from instruction
	    if (!extended)
		done = 1;
	    else {
		while (p2-S < 14)
		    *p2++ = ' ';
		*p2++ = ';';
		*p2++ = ' ';
	    }
	    break;

	case '!':
	    // print contents of register
	    ch = *p1++;
	    ASSERT(ch);
	    switch (ch) {
	    case 'B': sprintf(H, "%04X", I80Regs.nBC.W); break;
	    case 'D': sprintf(H, "%04X", I80Regs.nDE.W); break;
	    case 'H': sprintf(H, "%04X", I80Regs.nHL.W); break;
	    default: ASSERT(0);
	    }
	    strcpy(p2,H);
	    p2+=4;
	    break;

	case '@':
	    // print contents of register
	    ch = *p1++;
	    ASSERT(ch);
	    switch (ch) {
	    case 'b': addr = I80Regs.nBC.W; sprintf(H, "%02X", GetMem(addr)); break;
	    case 'd': addr = I80Regs.nDE.W; sprintf(H, "%02X", GetMem(addr)); break;
	    case 'h': addr = I80Regs.nHL.W; sprintf(H, "%02X", GetMem(addr)); break;
	    case '%': sprintf(H, "%02X", GetMem(imm16)); break;
	    case 'B': addr = I80Regs.nBC.W; sprintf(H, "%04X", GetMem(addr)+256*GetMem((word)(addr+1))); break;
	    case 'D': addr = I80Regs.nDE.W; sprintf(H, "%04X", GetMem(addr)+256*GetMem((word)(addr+1))); break;
	    case 'H': addr = I80Regs.nHL.W; sprintf(H, "%04X", GetMem(addr)+256*GetMem((word)(addr+1))); break;
	    case '#': sprintf(H, "%04X", GetMem(imm16)+256*GetMem((word)(imm16+1))); break;
	    default: ASSERT(0);
	    }
	    strcpy(p2,H);
	    p2+=strlen(H);
	    break;

	default:
	    *p2++ = ch;
	    break;

	} // switch

    } // while

    *p2 = '\0';

    return Len8080[op];
}

/* end of file: debug.c */
