/** 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==TRUE                       **/
/**                                                                        **/
/** Copyright (C) Marat Fayzullin 1995,1996                                **/
/**               Marcel de Kogel 1996                                     **/
/**     You are not allowed to distribute this software commercially       **/
/**     Please, notify me, if you make any changes to this file            **/
/****************************************************************************/

#ifdef DEBUG

#include "Z80.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>
#include <allegro.h>

#define	MEM1DEFAULT	0x9000
#define	MEM2DEFAULT	0x9800
#define	XRES	256
#define	YRES	256
#define	HEADING_COLOUR		LIGHTGREEN
#define	LINE_COLOUR			LIGHTCYAN
#define	REGISTER_COLOUR		WHITE
#define	FLAG_COLOUR			WHITE
#define	BREAKPOINT_COLOUR	YELLOW
#define	CODE_COLOUR			WHITE
#define	MEM1_COLOUR			WHITE
#define	MEM2_COLOUR			WHITE
#define	ERROR_COLOUR		RED
#define	PROMPT_COLOUR		CYAN
#define	INSTRUCTION_COLOUR	WHITE
#define	INPUT_COLOUR		WHITE

int DAsm(char *S,word A);

char *Mnemonics[256] =
{
  "NOP","LD BC,#h","LD (BC),A","INC BC","INC B","DEC B","LD B,*h","RLCA",
  "EX AF,AF'","ADD HL,BC","LD A,(BC)","DEC BC","INC C","DEC C","LD C,*h","RRCA",
  "DJNZ @h","LD DE,#h","LD (DE),A","INC DE","INC D","DEC D","LD D,*h","RLA",
  "JR @h","ADD HL,DE","LD A,(DE)","DEC DE","INC E","DEC E","LD E,*h","RRA",
  "JR NZ,@h","LD HL,#h","LD (#h),HL","INC HL","INC H","DEC H","LD H,*h","DAA",
  "JR Z,@h","ADD HL,HL","LD HL,(#h)","DEC HL","INC L","DEC L","LD L,*h","CPL",
  "JR NC,@h","LD SP,#h","LD (#h),A","INC SP","INC (HL)","DEC (HL)","LD (HL),*h","SCF",
  "JR C,@h","ADD HL,SP","LD A,(#h)","DEC SP","INC A","DEC A","LD A,*h","CCF",
  "LD B,B","LD B,C","LD B,D","LD B,E","LD B,H","LD B,L","LD B,(HL)","LD B,A",
  "LD C,B","LD C,C","LD C,D","LD C,E","LD C,H","LD C,L","LD C,(HL)","LD C,A",
  "LD D,B","LD D,C","LD D,D","LD D,E","LD D,H","LD D,L","LD D,(HL)","LD D,A",
  "LD E,B","LD E,C","LD E,D","LD E,E","LD E,H","LD E,L","LD E,(HL)","LD E,A",
  "LD H,B","LD H,C","LD H,D","LD H,E","LD H,H","LD H,L","LD H,(HL)","LD H,A",
  "LD L,B","LD L,C","LD L,D","LD L,E","LD L,H","LD L,L","LD L,(HL)","LD L,A",
  "LD (HL),B","LD (HL),C","LD (HL),D","LD (HL),E","LD (HL),H","LD (HL),L","HALT","LD (HL),A",
  "LD A,B","LD A,C","LD A,D","LD A,E","LD A,H","LD A,L","LD A,(HL)","LD A,A",
  "ADD B","ADD C","ADD D","ADD E","ADD H","ADD L","ADD (HL)","ADD A",
  "ADC B","ADC C","ADC D","ADC E","ADC H","ADC L","ADC (HL)","ADC A",
  "SUB B","SUB C","SUB D","SUB E","SUB H","SUB L","SUB (HL)","SUB A",
  "SBC B","SBC C","SBC D","SBC E","SBC H","SBC L","SBC (HL)","SBC A",
  "AND B","AND C","AND D","AND E","AND H","AND L","AND (HL)","AND A",
  "XOR B","XOR C","XOR D","XOR E","XOR H","XOR L","XOR (HL)","XOR A",
  "OR B","OR C","OR D","OR E","OR H","OR L","OR (HL)","OR A",
  "CP B","CP C","CP D","CP E","CP H","CP L","CP (HL)","CP A",
  "RET NZ","POP BC","JP NZ,#h","JP #h","CALL NZ,#h","PUSH BC","ADD *h","RST 00h",
  "RET Z","RET","JP Z,#h","PFX_CB","CALL Z,#h","CALL #h","ADC *h","RST 08h",
  "RET NC","POP DE","JP NC,#h","OUTA (*h)","CALL NC,#h","PUSH DE","SUB *h","RST 10h",
  "RET C","EXX","JP C,#h","INA (*h)","CALL C,#h","PFX_DD","SBC *h","RST 18h",
  "RET PO","POP HL","JP PO,#h","EX HL,(SP)","CALL PO,#h","PUSH HL","AND *h","RST 20h",
  "RET PE","LD PC,HL","JP PE,#h","EX DE,HL","CALL PE,#h","PFX_ED","XOR *h","RST 28h",
  "RET P","POP AF","JP P,#h","DI","CALL P,#h","PUSH AF","OR *h","RST 30h",
  "RET M","LD SP,HL","JP M,#h","EI","CALL M,#h","PFX_FD","CP *h","RST 38h"
};

char *MnemonicsCB[256] =
{
  "RLC B","RLC C","RLC D","RLC E","RLC H","RLC L","RLC (HL)","RLC A",
  "RRC B","RRC C","RRC D","RRC E","RRC H","RRC L","RRC (HL)","RRC A",
  "RL B","RL C","RL D","RL E","RL H","RL L","RL (HL)","RL A",
  "RR B","RR C","RR D","RR E","RR H","RR L","RR (HL)","RR A",
  "SLA B","SLA C","SLA D","SLA E","SLA H","SLA L","SLA (HL)","SLA A",
  "SRA B","SRA C","SRA D","SRA E","SRA H","SRA L","SRA (HL)","SRA A",
  "SLL B","SLL C","SLL D","SLL E","SLL H","SLL L","SLL (HL)","SLL A",
  "SRL B","SRL C","SRL D","SRL E","SRL H","SRL L","SRL (HL)","SRL A",
  "BIT 0,B","BIT 0,C","BIT 0,D","BIT 0,E","BIT 0,H","BIT 0,L","BIT 0,(HL)","BIT 0,A",
  "BIT 1,B","BIT 1,C","BIT 1,D","BIT 1,E","BIT 1,H","BIT 1,L","BIT 1,(HL)","BIT 1,A",
  "BIT 2,B","BIT 2,C","BIT 2,D","BIT 2,E","BIT 2,H","BIT 2,L","BIT 2,(HL)","BIT 2,A",
  "BIT 3,B","BIT 3,C","BIT 3,D","BIT 3,E","BIT 3,H","BIT 3,L","BIT 3,(HL)","BIT 3,A",
  "BIT 4,B","BIT 4,C","BIT 4,D","BIT 4,E","BIT 4,H","BIT 4,L","BIT 4,(HL)","BIT 4,A",
  "BIT 5,B","BIT 5,C","BIT 5,D","BIT 5,E","BIT 5,H","BIT 5,L","BIT 5,(HL)","BIT 5,A",
  "BIT 6,B","BIT 6,C","BIT 6,D","BIT 6,E","BIT 6,H","BIT 6,L","BIT 6,(HL)","BIT 6,A",
  "BIT 7,B","BIT 7,C","BIT 7,D","BIT 7,E","BIT 7,H","BIT 7,L","BIT 7,(HL)","BIT 7,A",
  "RES 0,B","RES 0,C","RES 0,D","RES 0,E","RES 0,H","RES 0,L","RES 0,(HL)","RES 0,A",
  "RES 1,B","RES 1,C","RES 1,D","RES 1,E","RES 1,H","RES 1,L","RES 1,(HL)","RES 1,A",
  "RES 2,B","RES 2,C","RES 2,D","RES 2,E","RES 2,H","RES 2,L","RES 2,(HL)","RES 2,A",
  "RES 3,B","RES 3,C","RES 3,D","RES 3,E","RES 3,H","RES 3,L","RES 3,(HL)","RES 3,A",
  "RES 4,B","RES 4,C","RES 4,D","RES 4,E","RES 4,H","RES 4,L","RES 4,(HL)","RES 4,A",
  "RES 5,B","RES 5,C","RES 5,D","RES 5,E","RES 5,H","RES 5,L","RES 5,(HL)","RES 5,A",
  "RES 6,B","RES 6,C","RES 6,D","RES 6,E","RES 6,H","RES 6,L","RES 6,(HL)","RES 6,A",
  "RES 7,B","RES 7,C","RES 7,D","RES 7,E","RES 7,H","RES 7,L","RES 7,(HL)","RES 7,A",
  "SET 0,B","SET 0,C","SET 0,D","SET 0,E","SET 0,H","SET 0,L","SET 0,(HL)","SET 0,A",
  "SET 1,B","SET 1,C","SET 1,D","SET 1,E","SET 1,H","SET 1,L","SET 1,(HL)","SET 1,A",
  "SET 2,B","SET 2,C","SET 2,D","SET 2,E","SET 2,H","SET 2,L","SET 2,(HL)","SET 2,A",
  "SET 3,B","SET 3,C","SET 3,D","SET 3,E","SET 3,H","SET 3,L","SET 3,(HL)","SET 3,A",
  "SET 4,B","SET 4,C","SET 4,D","SET 4,E","SET 4,H","SET 4,L","SET 4,(HL)","SET 4,A",
  "SET 5,B","SET 5,C","SET 5,D","SET 5,E","SET 5,H","SET 5,L","SET 5,(HL)","SET 5,A",
  "SET 6,B","SET 6,C","SET 6,D","SET 6,E","SET 6,H","SET 6,L","SET 6,(HL)","SET 6,A",
  "SET 7,B","SET 7,C","SET 7,D","SET 7,E","SET 7,H","SET 7,L","SET 7,(HL)","SET 7,A"
};

char *MnemonicsED[256] =
{
  "DB EDh,00h","DB EDh,01h","DB EDh,02h","DB EDh,03h",
  "DB EDh,04h","DB EDh,05h","DB EDh,06h","DB EDh,07h",
  "DB EDh,08h","DB EDh,09h","DB EDh,0Ah","DB EDh,0Bh",
  "DB EDh,0Ch","DB EDh,0Dh","DB EDh,0Eh","DB EDh,0Fh",
  "DB EDh,10h","DB EDh,11h","DB EDh,12h","DB EDh,13h",
  "DB EDh,14h","DB EDh,15h","DB EDh,16h","DB EDh,17h",
  "DB EDh,18h","DB EDh,19h","DB EDh,1Ah","DB EDh,1Bh",
  "DB EDh,1Ch","DB EDh,1Dh","DB EDh,1Eh","DB EDh,1Fh",
  "DB EDh,20h","DB EDh,21h","DB EDh,22h","DB EDh,23h",
  "DB EDh,24h","DB EDh,25h","DB EDh,26h","DB EDh,27h",
  "DB EDh,28h","DB EDh,29h","DB EDh,2Ah","DB EDh,2Bh",
  "DB EDh,2Ch","DB EDh,2Dh","DB EDh,2Eh","DB EDh,2Fh",
  "DB EDh,30h","DB EDh,31h","DB EDh,32h","DB EDh,33h",
  "DB EDh,34h","DB EDh,35h","DB EDh,36h","DB EDh,37h",
  "DB EDh,38h","DB EDh,39h","DB EDh,3Ah","DB EDh,3Bh",
  "DB EDh,3Ch","DB EDh,3Dh","DB EDh,3Eh","DB EDh,3Fh",
  "IN B,(C)","OUT (C),B","SBC HL,BC","LD (#h),BC",
  "DB EDh,44h","RETN","IM 0","LD I,A",
  "IN C,(C)","OUT (C),C","ADC HL,BC","LD BC,(#h)",
  "DB EDh,4Ch","RETI","DB EDh,4Eh","LD R,A",
  "IN D,(C)","OUT (C),D","SBC HL,DE","LD (#h),DE",
  "DB EDh,54h","DB EDh,55h","IM 1","LD A,I",
  "IN E,(C)","OUT (C),E","ADC HL,DE","LD DE,(#h)",
  "DB EDh,5Ch","DB EDh,5Dh","IM 2","LD A,R",
  "IN H,(C)","OUT (C),H","SBC HL,HL","LD (#h),HL",
  "DB EDh,64h","DB EDh,65h","DB EDh,66h","RRD",
  "IN L,(C)","OUT (C),L","ADC HL,HL","LD HL,(#h)",
  "DB EDh,6Ch","DB EDh,6Dh","DB EDh,6Eh","RLD",
  "IN F,(C)","DB EDh,71h","SBC HL,SP","LD (#h),SP",
  "DB EDh,74h","DB EDh,75h","DB EDh,76h","DB EDh,77h",
  "IN A,(C)","OUT (C),A","ADC HL,SP","LD SP,(#h)",
  "DB EDh,7Ch","DB EDh,7Dh","DB EDh,7Eh","DB EDh,7Fh",
  "DB EDh,80h","DB EDh,81h","DB EDh,82h","DB EDh,83h",
  "DB EDh,84h","DB EDh,85h","DB EDh,86h","DB EDh,87h",
  "DB EDh,88h","DB EDh,89h","DB EDh,8Ah","DB EDh,8Bh",
  "DB EDh,8Ch","DB EDh,8Dh","DB EDh,8Eh","DB EDh,8Fh",
  "DB EDh,90h","DB EDh,91h","DB EDh,92h","DB EDh,93h",
  "DB EDh,94h","DB EDh,95h","DB EDh,96h","DB EDh,97h",
  "DB EDh,98h","DB EDh,99h","DB EDh,9Ah","DB EDh,9Bh",
  "DB EDh,9Ch","DB EDh,9Dh","DB EDh,9Eh","DB EDh,9Fh",
  "LDI","CPI","INI","OUTI",
  "DB EDh,A4h","DB EDh,A5h","DB EDh,A6h","DB EDh,A7h",
  "LDD","CPD","IND","OUTD",
  "DB EDh,ACh","DB EDh,ADh","DB EDh,AEh","DB EDh,AFh",
  "LDIR","CPIR","INIR","OTIR",
  "DB EDh,B4h","DB EDh,B5h","DB EDh,B6h","DB EDh,B7h",
  "LDDR","CPDR","INDR","OTDR",
  "DB EDh,BCh","DB EDh,BDh","DB EDh,BEh","DB EDh,BFh",
  "DB EDh,C0h","DB EDh,C1h","DB EDh,C2h","DB EDh,C3h",
  "DB EDh,C4h","DB EDh,C5h","DB EDh,C6h","DB EDh,C7h",
  "DB EDh,C8h","DB EDh,C9h","DB EDh,CAh","DB EDh,CBh",
  "DB EDh,CCh","DB EDh,CDh","DB EDh,CEh","DB EDh,CFh",
  "DB EDh,D0h","DB EDh,D1h","DB EDh,D2h","DB EDh,D3h",
  "DB EDh,D4h","DB EDh,D5h","DB EDh,D6h","DB EDh,D7h",
  "DB EDh,D8h","DB EDh,D9h","DB EDh,DAh","DB EDh,DBh",
  "DB EDh,DCh","DB EDh,DDh","DB EDh,DEh","DB EDh,DFh",
  "DB EDh,E0h","DB EDh,E1h","DB EDh,E2h","DB EDh,E3h",
  "DB EDh,E4h","DB EDh,E5h","DB EDh,E6h","DB EDh,E7h",
  "DB EDh,E8h","DB EDh,E9h","DB EDh,EAh","DB EDh,EBh",
  "DB EDh,ECh","DB EDh,EDh","DB EDh,EEh","DB EDh,EFh",
  "DB EDh,F0h","DB EDh,F1h","DB EDh,F2h","DB EDh,F3h",
  "DB EDh,F4h","DB EDh,F5h","DB EDh,F6h","DB EDh,F7h",
  "DB EDh,F8h","DB EDh,F9h","DB EDh,FAh","DB EDh,FBh",
  "DB EDh,FCh","DB EDh,FDh","DB EDh,FEh","DB EDh,FFh"
};

char *MnemonicsXX[256] =
{
  "NOP","LD BC,#h","LD (BC),A","INC BC","INC B","DEC B","LD B,*h","RLCA",
  "EX AF,AF'","ADD I%,BC","LD A,(BC)","DEC BC","INC C","DEC C","LD C,*h","RRCA",
  "DJNZ @h","LD DE,#h","LD (DE),A","INC DE","INC D","DEC D","LD D,*h","RLA",
  "JR @h","ADD I%,DE","LD A,(DE)","DEC DE","INC E","DEC E","LD E,*h","RRA",
  "JR NZ,@h","LD I%,#h","LD (#h),I%","INC I%","INC I%h","DEC I%h","LD I%h,*h","DAA",
  "JR Z,@h","ADD I%,I%","LD I%,(#h)","DEC I%","INC I%l","DEC I%l","LD I%l,*h","CPL",
  "JR NC,@h","LD SP,#h","LD (#h),A","INC SP","INC (I%+^h)","DEC (I%+^h)","LD (I%+^h),*h","SCF",
  "JR C,@h","ADD I%,SP","LD A,(#h)","DEC SP","INC A","DEC A","LD A,*h","CCF",
  "LD B,B","LD B,C","LD B,D","LD B,E","LD B,I%h","LD B,I%l","LD B,(I%+^h)","LD B,A",
  "LD C,B","LD C,C","LD C,D","LD C,E","LD C,I%h","LD C,I%l","LD C,(I%+^h)","LD C,A",
  "LD D,B","LD D,C","LD D,D","LD D,E","LD D,I%h","LD D,I%l","LD D,(I%+^h)","LD D,A",
  "LD E,B","LD E,C","LD E,D","LD E,E","LD E,I%h","LD E,I%l","LD E,(I%+^h)","LD E,A",
  "LD I%h,B","LD I%h,C","LD I%h,D","LD I%h,E","LD I%h,I%h","LD I%h,I%l","LD H,(I%+^h)","LD I%h,A",
  "LD I%l,B","LD I%l,C","LD I%l,D","LD I%l,E","LD I%l,I%h","LD I%l,I%l","LD L,(I%+^h)","LD I%l,A",
  "LD (I%+^h),B","LD (I%+^h),C","LD (I%+^h),D","LD (I%+^h),E","LD (I%+^h),H","LD (I%+^h),L","HALT","LD (I%+^h),A",
  "LD A,B","LD A,C","LD A,D","LD A,E","LD A,I%h","LD A,I%l","LD A,(I%+^h)","LD A,A",
  "ADD B","ADD C","ADD D","ADD E","ADD I%h","ADD I%l","ADD (I%+^h)","ADD A",
  "ADC B","ADC C","ADC D","ADC E","ADC I%h","ADC I%l","ADC (I%+^h)","ADC,A",
  "SUB B","SUB C","SUB D","SUB E","SUB I%h","SUB I%l","SUB (I%+^h)","SUB A",
  "SBC B","SBC C","SBC D","SBC E","SBC I%h","SBC I%l","SBC (I%+^h)","SBC A",
  "AND B","AND C","AND D","AND E","AND I%h","AND I%l","AND (I%+^h)","AND A",
  "XOR B","XOR C","XOR D","XOR E","XOR I%h","XOR I%l","XOR (I%+^h)","XOR A",
  "OR B","OR C","OR D","OR E","OR I%h","OR I%l","OR (I%+^h)","OR A",
  "CP B","CP C","CP D","CP E","CP I%h","CP I%l","CP (I%+^h)","CP A",
  "RET NZ","POP BC","JP NZ,#h","JP #h","CALL NZ,#h","PUSH BC","ADD *h","RST 00h",
  "RET Z","RET","JP Z,#h","PFX_CB","CALL Z,#h","CALL #h","ADC *h","RST 08h",
  "RET NC","POP DE","JP NC,#h","OUTA (*h)","CALL NC,#h","PUSH DE","SUB *h","RST 10h",
  "RET C","EXX","JP C,#h","INA (*h)","CALL C,#h","PFX_DD","SBC *h","RST 18h",
  "RET PO","POP I%","JP PO,#h","EX I%,(SP)","CALL PO,#h","PUSH I%","AND *h","RST 20h",
  "RET PE","LD PC,I%","JP PE,#h","EX DE,I%","CALL PE,#h","PFX_ED","XOR *h","RST 28h",
  "RET P","POP AF","JP P,#h","DI","CALL P,#h","PUSH AF","OR *h","RST 30h",
  "RET M","LD SP,I%","JP M,#h","EI","CALL M,#h","PFX_FD","CP *h","RST 38h"
};

char *MnemonicsXCB[256] =
{
  "RLC B","RLC C","RLC D","RLC E","RLC H","RLC L","RLC (I%@h)","RLC A",
  "RRC B","RRC C","RRC D","RRC E","RRC H","RRC L","RRC (I%@h)","RRC A",
  "RL B","RL C","RL D","RL E","RL H","RL L","RL (I%@h)","RL A",
  "RR B","RR C","RR D","RR E","RR H","RR L","RR (I%@h)","RR A",
  "SLA B","SLA C","SLA D","SLA E","SLA H","SLA L","SLA (I%@h)","SLA A",
  "SRA B","SRA C","SRA D","SRA E","SRA H","SRA L","SRA (I%@h)","SRA A",
  "SLL B","SLL C","SLL D","SLL E","SLL H","SLL L","SLL (I%@h)","SLL A",
  "SRL B","SRL C","SRL D","SRL E","SRL H","SRL L","SRL (I%@h)","SRL A",
  "BIT 0,B","BIT 0,C","BIT 0,D","BIT 0,E","BIT 0,H","BIT 0,L","BIT 0,(I%@h)","BIT 0,A",
  "BIT 1,B","BIT 1,C","BIT 1,D","BIT 1,E","BIT 1,H","BIT 1,L","BIT 1,(I%@h)","BIT 1,A",
  "BIT 2,B","BIT 2,C","BIT 2,D","BIT 2,E","BIT 2,H","BIT 2,L","BIT 2,(I%@h)","BIT 2,A",
  "BIT 3,B","BIT 3,C","BIT 3,D","BIT 3,E","BIT 3,H","BIT 3,L","BIT 3,(I%@h)","BIT 3,A",
  "BIT 4,B","BIT 4,C","BIT 4,D","BIT 4,E","BIT 4,H","BIT 4,L","BIT 4,(I%@h)","BIT 4,A",
  "BIT 5,B","BIT 5,C","BIT 5,D","BIT 5,E","BIT 5,H","BIT 5,L","BIT 5,(I%@h)","BIT 5,A",
  "BIT 6,B","BIT 6,C","BIT 6,D","BIT 6,E","BIT 6,H","BIT 6,L","BIT 6,(I%@h)","BIT 6,A",
  "BIT 7,B","BIT 7,C","BIT 7,D","BIT 7,E","BIT 7,H","BIT 7,L","BIT 7,(I%@h)","BIT 7,A",
  "RES 0,B","RES 0,C","RES 0,D","RES 0,E","RES 0,H","RES 0,L","RES 0,(I%@h)","RES 0,A",
  "RES 1,B","RES 1,C","RES 1,D","RES 1,E","RES 1,H","RES 1,L","RES 1,(I%@h)","RES 1,A",
  "RES 2,B","RES 2,C","RES 2,D","RES 2,E","RES 2,H","RES 2,L","RES 2,(I%@h)","RES 2,A",
  "RES 3,B","RES 3,C","RES 3,D","RES 3,E","RES 3,H","RES 3,L","RES 3,(I%@h)","RES 3,A",
  "RES 4,B","RES 4,C","RES 4,D","RES 4,E","RES 4,H","RES 4,L","RES 4,(I%@h)","RES 4,A",
  "RES 5,B","RES 5,C","RES 5,D","RES 5,E","RES 5,H","RES 5,L","RES 5,(I%@h)","RES 5,A",
  "RES 6,B","RES 6,C","RES 6,D","RES 6,E","RES 6,H","RES 6,L","RES 6,(I%@h)","RES 6,A",
  "RES 7,B","RES 7,C","RES 7,D","RES 7,E","RES 7,H","RES 7,L","RES 7,(I%@h)","RES 7,A",
  "SET 0,B","SET 0,C","SET 0,D","SET 0,E","SET 0,H","SET 0,L","SET 0,(I%@h)","SET 0,A",
  "SET 1,B","SET 1,C","SET 1,D","SET 1,E","SET 1,H","SET 1,L","SET 1,(I%@h)","SET 1,A",
  "SET 2,B","SET 2,C","SET 2,D","SET 2,E","SET 2,H","SET 2,L","SET 2,(I%@h)","SET 2,A",
  "SET 3,B","SET 3,C","SET 3,D","SET 3,E","SET 3,H","SET 3,L","SET 3,(I%@h)","SET 3,A",
  "SET 4,B","SET 4,C","SET 4,D","SET 4,E","SET 4,H","SET 4,L","SET 4,(I%@h)","SET 4,A",
  "SET 5,B","SET 5,C","SET 5,D","SET 5,E","SET 5,H","SET 5,L","SET 5,(I%@h)","SET 5,A",
  "SET 6,B","SET 6,C","SET 6,D","SET 6,E","SET 6,H","SET 6,L","SET 6,(I%@h)","SET 6,A",
  "SET 7,B","SET 7,C","SET 7,D","SET 7,E","SET 7,H","SET 7,L","SET 7,(I%@h)","SET 7,A"
};

int DAsm(char *S,word A)
{
  char R[128],H[10],C,*T,*P;
  byte J;
	byte	Offset = 0;
  word B;

  B=A;C='\0';J=0;

  switch(M_RDMEM(B))
  {
    case 0xCB: B++;T=MnemonicsCB[M_RDMEM(B++)];break;
    case 0xED: B++;T=MnemonicsED[M_RDMEM(B++)];break;
    case 0xDD: B++;C='X';
               if(M_RDMEM(B)!=0xCB) T=MnemonicsXX[M_RDMEM(B++)];
               else
               { B++;Offset=M_RDMEM(B++);J=1;T=MnemonicsXCB[M_RDMEM(B++)]; }
               break;
    case 0xFD: B++;C='Y';
               if(M_RDMEM(B)!=0xCB) T=MnemonicsXX[M_RDMEM(B++)];
               else
               { B++;Offset=M_RDMEM(B++);J=1;T=MnemonicsXCB[M_RDMEM(B++)]; }
               break;
    default:   T=Mnemonics[M_RDMEM(B++)];
  }

  if((P=strchr(T,'^')))
  {
    strncpy(R,T,P-T);R[P-T]='\0';
    sprintf(H,"%02X",M_RDMEM(B++));
    strcat(R,H);strcat(R,P+1);
  }
  else strcpy(R,T);
  if((P=strchr(R,'%')))
	*P=C;

  if((P=strchr(R,'*')))
  {
    strncpy(S,R,P-R);S[P-R]='\0';
    sprintf(H,"%02X",M_RDMEM(B++));
    strcat(S,H);strcat(S,P+1);
  }
  else
    if((P=strchr(R,'@')))
    {
      strncpy(S,R,P-R);S[P-R]='\0';
      if(!J) Offset=M_RDMEM(B++);
      strcat(S,Offset&0x80? "-":"+");
      J=Offset&0x80? 256-Offset:Offset;
      sprintf(H,"%02X",J);
      strcat(S,H);strcat(S,P+1);
    }
    else
      if((P=strchr(R,'#')))
      {
        strncpy(S,R,P-R);S[P-R]='\0';
        sprintf(H,"%04X",M_RDMEM(B)+256*M_RDMEM(B+1));
        strcat(S,H);strcat(S,P+1);
        B+=2;
      }
      else strcpy(S,R);

  return(B-A);
}

// Draw the screen outline

void
DrawDebugScreen(int TextCol, int LineCol)
{
	int		y;

	ScreenPutString("ษออ           อออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออป", LineCol, 0, 0);
	ScreenPutString("Registers", TextCol, 4, 0);
	ScreenPutString("บ", LineCol, 0, 1);
	ScreenPutString("บ", LineCol, 79, 1);
	ScreenPutString("ฬออ       อออออออออออออหออ          อออออออออออออออออออออออออออออออออออออออออออน", LineCol, 0, 2);
	ScreenPutString("Flags", TextCol, 4, 2);
	ScreenPutString("Memory 1", TextCol, 27, 2);
	ScreenPutString("บ", LineCol, 0, 3);
	ScreenPutString("บ", LineCol, 23, 3);
	ScreenPutString("บ", LineCol, 79, 3);
	ScreenPutString("ฬออ      ออออออออออออออน", LineCol, 0, 4);
	ScreenPutString("Code", TextCol, 4, 4);
	ScreenPutString("บ", LineCol, 79, 4);
	for (y = 5; y < 11; y++)
	{
		ScreenPutString("บ", LineCol, 0, y);
		ScreenPutString("บ", LineCol, 23, y);
		ScreenPutString("บ", LineCol, 79, y);
	}
	ScreenPutString("บ", LineCol, 0, 11);
	ScreenPutString("ฬออ          อออออออออออออออออออออออออออออออออออออออออออน", LineCol, 23, 11);
	ScreenPutString("Memory 2", TextCol, 27, 11);
	for (y = 12; y < 20; y++)
	{
		ScreenPutString("บ", LineCol, 0, y);
		ScreenPutString("บ", LineCol, 23, y);
		ScreenPutString("บ", LineCol, 79, y);
	}
	ScreenPutString("ฬออ         อออออออออออสอออออออออออออออออออออออออออออออออออออออออออออออออออออออน", LineCol, 0, 20);
	ScreenPutString("Command", TextCol, 4, 20);
	for (y = 21; y < 24; y++)
	{
		ScreenPutString("บ", LineCol, 0, y);
		ScreenPutString("บ", LineCol, 79, y);
	}
	ScreenPutString("ศออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออผ", LineCol, 0, 24);
}

// Get a Number
int
GetNumber(int X, int Y, int Col)
{
	char	Num[16];
	int		Pos = 0;
	int		Key;

	Num[Pos] = '\0';
	ScreenSetCursor(Y, X);
	ScreenPutString("        ", Col, X, Y);
	while ((Key = (readkey()) & 0xff) != '\r')
	{
		Key = toupper(Key);
		switch(Key)
		{
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
			case 'A':
			case 'B':
			case 'C':
			case 'D':
			case 'E':
			case 'F':
				Num[Pos++] = Key;
				Num[Pos] = '\0';
				break;
			case '\b':
				if (Pos > 0)
				{
					Pos--;
					Num[Pos] = '\0';
				}
				break;
			default:
				Key = 0;
				break;
		}
		if (Key)
		{
			ScreenPutString("        ", Col, X + Pos, Y);
			ScreenPutString(Num, Col, X, Y);
			ScreenSetCursor(Y, X + Pos);
		}
	}
	ScreenPutString("        ", Col, X, Y);
	return(strtol(Num, NULL, 16));
}

/*** Single-step debugger ****************************/
/*** This function should exist if DEBUG is        ***/
/*** #defined. When Trace=TRUE, it is called after ***/
/*** each command executed by the CPU and given    ***/
/*** a pointer to the register file.               ***/
/*****************************************************/

word MEM1 = MEM1DEFAULT;
word MEM2 = MEM2DEFAULT;

void Debug(reg *R)
{
	int			x, y;
	static int	InDebug=FALSE;
	static int	Update;
	static int	Step;
	static int	DebugTrace = FALSE;
	static int	BreakPointValid = FALSE;
	static word	BreakPoint = 0;
	dword		ADD;
	byte		VAL;
	int			Key;
	int			Colour;
	int			InvalidKey;
	static char	Flags[8] = "SZ.H.PNC";
	char		S[128],T[10];
	byte		J,I;
	word		PC;

// Check for breakpoint of F1 key to enter debugger
	if ((BreakPointValid && (R->PC.W.l == BreakPoint)) || key[KEY_F1])
	{
		clear_keybuf();
		set_gfx_mode(GFX_TEXT,80,25,0,0);
		DrawDebugScreen(HEADING_COLOUR, LINE_COLOUR);
		InDebug = TRUE;
		Update = TRUE;
		DebugTrace = FALSE;
	}
	Step = FALSE;		// So that we will get back into debugger if needed
	Update = TRUE;		// Cause a screen refresh
	while ((InDebug) && !Step)
	{
		if (Update)
		{
			for(J=0,I=R->AF.B.l;J<8;J++,I<<=1)
				T[J]=I&0x80? Flags[J]:'.';
			T[8]='\0';
			sprintf(S, "AF:%04X HL:%04X DE:%04X BC:%04X PC:%04X SP:%04X IX:%04X IY:%04X I:%02X R:%02X",
				R->AF.W.l, R->HL.W.l, R->DE.W.l, R->BC.W.l, R->PC.W.l,
				R->SP.W.l, R->IX.W.l, R->IY.W.l, R->I, R->R);
			ScreenPutString(S, REGISTER_COLOUR, 2, 1);
			ScreenPutString(T, FLAG_COLOUR, 2, 3);
			PC = R->PC.W.l;
			for(y = 0; y < 15; y++)
			{
				if (BreakPointValid && (PC == BreakPoint))
					Colour = BREAKPOINT_COLOUR;
				else
					Colour = CODE_COLOUR;
				sprintf(S, "%04X:               ", PC);
				ScreenPutString(S, Colour, 2, y + 5);
				PC += DAsm(S, PC);
				ScreenPutString(S, Colour, 8, y + 5);
			}
			PC = MEM1;
			for (y = 0; y < 8; y++)
			{
				sprintf(S, "%04X:", PC);
				ScreenPutString(S, MEM1_COLOUR, 25, y + 3);
				for (x = 0; x < 16; x++)
				{
					sprintf(S, "%02X", M_RDMEM(PC++));
					ScreenPutString(S, MEM1_COLOUR, 31 + (x * 3), y + 3);
				}
			}
			PC = MEM2;
			for (y = 0; y < 8; y++)
			{
				sprintf(S, "%04X:", PC);
				ScreenPutString(S, MEM2_COLOUR, 25, y + 12);
				for (x = 0; x < 16; x++)
				{
					sprintf(S, "%02X", M_RDMEM(PC++));
					ScreenPutString(S, MEM2_COLOUR, 31 + (x * 3), y + 12);
				}
			}
			ScreenPutString("Command>", PROMPT_COLOUR, 2, 21);
			ScreenSetCursor(21, 10);
			Update = FALSE;
		}

		if (!DebugTrace)
		{
			Key = readkey();
			ScreenPutString("                                              ",
				INSTRUCTION_COLOUR, 2, 22);
			InvalidKey = FALSE;		// Assume a valid key
			sprintf(S, "%c", Key & 0xff);
			ScreenPutString(S, INPUT_COLOUR, 10, 21);
			switch (Key & 0xff)
			{
				case '1':
					ScreenPutString("Enter new address for memory 1",
						INSTRUCTION_COLOUR, 2, 22);
					MEM1 = GetNumber(10, 21, INPUT_COLOUR);
					Update = TRUE;
					break;
				case '2':
					ScreenPutString("Enter new address for memory 2",
						INSTRUCTION_COLOUR, 2, 22);
					MEM2 = GetNumber(10, 21, INPUT_COLOUR);
					Update = TRUE;
					break;
				case 'b':
				case 'B':
					ScreenPutString("Enter new breakpoint address",
						INSTRUCTION_COLOUR, 2, 22);
					BreakPoint = GetNumber(10, 21, INPUT_COLOUR);
					BreakPointValid = TRUE;
					Update = TRUE;
					break;
				case 'c':
				case 'C':
					Update = FALSE;
					InDebug = FALSE;
					set_gfx_mode(GFX_AUTODETECT,XRES,YRES,0,0);
					break;
				case 'd':
				case 'D':
					BreakPointValid = FALSE;
					Update = TRUE;
					break;
				case 'e':
				case 'E':
					ScreenPutString("Enter address to edit",
						INSTRUCTION_COLOUR, 2, 22);
					ADD = GetNumber(10, 21, INPUT_COLOUR);
					ScreenPutString("Enter New Value      ",
						INSTRUCTION_COLOUR, 2, 22);
					VAL = GetNumber(10, 21, INPUT_COLOUR);
					M_WRMEM(ADD, VAL);
					Update = TRUE;
					break;
				case 'r':
				case 'R':
					ScreenPutString("Change which register ?",
						INSTRUCTION_COLOUR, 2, 22);
					readkey();
					Update = TRUE;
					break;
				case 's':
				case 'S':
				case ' ':
				case '\r':
					Step = TRUE;
					break;
				case 't':
				case 'T':
					DebugTrace = TRUE;
					Step = TRUE;
					break;
				case 'v':
				case 'V':
					set_gfx_mode(GFX_AUTODETECT,XRES,YRES,0,0);
					Interrupt();
					while (!readkey())
						continue;		// do nothing
					set_gfx_mode(GFX_TEXT,80,25,0,0);
					DrawDebugScreen(HEADING_COLOUR, LINE_COLOUR);
					Update = TRUE;
					break;
				case 27:	// ESC
					CPURunning = 0;
					InDebug = FALSE;
					break;
				default:
					InvalidKey = TRUE;
					break;
			}
			if (InvalidKey)
			{
				ScreenPutString("Unknown Command", ERROR_COLOUR, 2, 22);
			}
			else
			{
				ScreenPutString(" ", INPUT_COLOUR, 10, 21);
				ScreenPutString("                                             ",
					INSTRUCTION_COLOUR, 2, 22);
			}
		}
		else
		{
			Step = TRUE;
			if (keypressed())
			{
				clear_keybuf();
				DebugTrace = FALSE;
			}
		}
	}
// Do a final check for exit
	if (key[KEY_ESC])
		CPURunning = 0;
}

#endif
