/** ** Supermodel ** A Sega Model 3 Arcade Emulator. ** Copyright 2011 Bart Trzynadlowski, Nik Henson ** ** This file is part of Supermodel. ** ** Supermodel is free software: you can redistribute it and/or modify it under ** the terms of the GNU General Public License as published by the Free ** Software Foundation, either version 3 of the License, or (at your option) ** any later version. ** ** Supermodel is distributed in the hope that it will be useful, but WITHOUT ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ** more details. ** ** You should have received a copy of the GNU General Public License along ** with Supermodel. If not, see . **/ /* * Z80Debug.cpp */ #ifdef SUPERMODEL_DEBUGGER #include "Z80Debug.h" #include "CPU/Z80/Z80.h" #include namespace Debugger { // Instruction templates static char *templates[5][256] = { { // Table 0: single byte instructions "NOP","LD BC,@a","LD (BC),A","INC BC","INC B","DEC B","LD B,@d","RLCA", "EX AF,AF'","ADD HL,BC","LD A,(BC)","DEC BC","INC C","DEC C","LD C,@d","RRCA", "DJNZ @b","LD DE,@a","LD (DE),A","INC DE","INC D","DEC D","LD D,@d","RLA", "JR @b","ADD HL,DE","LD A,(DE)","DEC DE","INC E","DEC E","LD E,@d","RRA", "JR NZ,@b","LD HL,@a","LD (@a),HL","INC HL","INC H","DEC H","LD H,@d","DAA", "JR Z,@b","ADD HL,HL","LD HL,(@a)","DEC HL","INC L","DEC L","LD L,@d","CPL", "JR NC,@b","LD SP,@a","LD (@a),A","INC SP","INC (HL)","DEC (HL)","LD (HL),@d","SCF", "JR C,@b","ADD HL,SP","LD A,(@a)","DEC SP","INC A","DEC A","LD A,@d","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,@j","JP @j","CALL NZ,@j","PUSH BC","ADD @d","RST 00h", "RET Z","RET","JP Z,@j","PFX_CB","CALL Z,@j","CALL @j","ADC @d","RST 08h", "RET NC","POP DE","JP NC,@j","OUTA (@p)","CALL NC,@j","PUSH DE","SUB @d","RST 10h", "RET C","EXX","JP C,@j","INA (@p)","CALL C,@j","PFX_DD","SBC @d","RST 18h", "RET PO","POP HL","JP PO,@j","EX HL,(SP)","CALL PO,@j","PUSH HL","AND @d","RST 20h", "RET PE","LD PC,HL","JP PE,@j","EX DE,HL","CALL PE,@j","PFX_ED","XOR @d","RST 28h", "RET P","POP AF","JP P,@j","DI","CALL P,@j","PUSH AF","OR @d","RST 30h", "RET M","LD SP,HL","JP M,@j","EI","CALL M,@j","PFX_FD","CP @d","RST 38h" }, { // Table 1: two byte instructions of form CB-XX "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" }, { // Table 2: two byte instructions of form ED-XX NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, "IN B,(C)","OUT (C),B","SBC HL,BC","LD (@a),BC","NEG","RETN","IM 0","LD I,A", "IN C,(C)","OUT (C),C","ADC HL,BC","LD BC,(@a)",NULL,"RETI",NULL,"LD R,A", "IN D,(C)","OUT (C),D","SBC HL,DE","LD (@a),DE",NULL,NULL,"IM 1","LD A,I", "IN E,(C)","OUT (C),E","ADC HL,DE","LD DE,(@a)",NULL,NULL,"IM 2","LD A,R", "IN H,(C)","OUT (C),H","SBC HL,HL","LD (@a),HL",NULL,NULL,NULL,"RRD", "IN L,(C)","OUT (C),L","ADC HL,HL","LD HL,(@a)",NULL,NULL,NULL,"RLD", "IN F,(C)",NULL,"SBC HL,SP","LD (@a),SP",NULL,NULL,NULL,NULL, "IN A,(C)","OUT (C),A","ADC HL,SP","LD SP,(@a)",NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, "LDI","CPI","INI","OUTI",NULL,NULL,NULL,NULL, "LDD","CPD","IND","OUTD",NULL,NULL,NULL,NULL, "LDIR","CPIR","INIR","OTIR",NULL,NULL,NULL,NULL, "LDDR","CPDR","INDR","OTDR",NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }, { // Table 3: two byte instructions of form DD-XX or FD-XX "NOP","LD BC,@a","LD (BC),A","INC BC","INC B","DEC B","LD B,@d","RLCA", "EX AF,AF'","ADD I?,BC","LD A,(BC)","DEC BC","INC C","DEC C","LD C,@d","RRCA", "DJNZ @b","LD DE,@a","LD (DE),A","INC DE","INC D","DEC D","LD D,@d","RLA", "JR @b","ADD I?,DE","LD A,(DE)","DEC DE","INC E","DEC E","LD E,@d","RRA", "JR NZ,@b","LD I?,@a","LD (@a),I?","INC I?","INC I?h","DEC I?h","LD I?h,@d","DAA", "JR Z,@b","ADD I?,I?","LD I?,(@a)","DEC I?","INC I?l","DEC I?l","LD I?l,@d","CPL", "JR NC,@b","LD SP,@a","LD (@a),A","INC SP","INC (I?+@d)","DEC (I?+@d)","LD (I?+@d),@d","SCF", "JR C,@b","ADD I?,SP","LD A,(@a)","DEC SP","INC A","DEC A","LD A,@d","CCF", "LD B,B","LD B,C","LD B,D","LD B,E","LD B,I?h","LD B,I?l","LD B,(I?+@d)","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?+@d)","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?+@d)","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?+@d)","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?+@d)","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?+@d)","LD I?l,A", "LD (I?+@d),B","LD (I?+@d),C","LD (I?+@d),D","LD (I?+@d),E","LD (I?+@d),H","LD (I?+@d),L","HALT","LD (I?+@d),A", "LD A,B","LD A,C","LD A,D","LD A,E","LD A,I?h","LD A,I?l","LD A,(I?+@d)","LD A,A", "ADD B","ADD C","ADD D","ADD E","ADD I?h","ADD I?l","ADD (I?+@d)","ADD A", "ADC B","ADC C","ADC D","ADC E","ADC I?h","ADC I?l","ADC (I?+@d)","ADC,A", "SUB B","SUB C","SUB D","SUB E","SUB I?h","SUB I?l","SUB (I?+@d)","SUB A", "SBC B","SBC C","SBC D","SBC E","SBC I?h","SBC I?l","SBC (I?+@d)","SBC A", "AND B","AND C","AND D","AND E","AND I?h","AND I?l","AND (I?+@d)","AND A", "XOR B","XOR C","XOR D","XOR E","XOR I?h","XOR I?l","XOR (I?+@d)","XOR A", "OR B","OR C","OR D","OR E","OR I?h","OR I?l","OR (I?+@d)","OR A", "CP B","CP C","CP D","CP E","CP I?h","CP I?l","CP (I?+@d)","CP A", "RET NZ","POP BC","JP NZ,@a","JP @a","CALL NZ,@a","PUSH BC","ADD @d","RST 00h", "RET Z","RET","JP Z,@a","PFX_CB","CALL Z,@a","CALL @a","ADC @d","RST 08h", "RET NC","POP DE","JP NC,@a","OUTA (@p)","CALL NC,@a","PUSH DE","SUB @d","RST 10h", "RET C","EXX","JP C,@a","INA (@p)","CALL C,@a","PFX_DD","SBC @d","RST 18h", "RET PO","POP I?","JP PO,@a","EX I?,(SP)","CALL PO,@a","PUSH I?","AND @d","RST 20h", "RET PE","LD PC,I?","JP PE,@a","EX DE,I?","CALL PE,@a","PFX_ED","XOR @d","RST 28h", "RET P","POP AF","JP P,@a","DI","CALL P,@a","PUSH AF","OR @d","RST 30h", "RET M","LD SP,I?","JP M,@a","EI","CALL M,@a","PFX_FD","CP @d","RST 38h" }, { // Table 4: three byte instructions of form DD-CB-XX or FD-CB-XX "RLC B","RLC C","RLC D","RLC E","RLC H","RLC L","RLC (I?@o)","RLC A", "RRC B","RRC C","RRC D","RRC E","RRC H","RRC L","RRC (I?@o)","RRC A", "RL B","RL C","RL D","RL E","RL H","RL L","RL (I?@o)","RL A", "RR B","RR C","RR D","RR E","RR H","RR L","RR (I?@o)","RR A", "SLA B","SLA C","SLA D","SLA E","SLA H","SLA L","SLA (I?@o)","SLA A", "SRA B","SRA C","SRA D","SRA E","SRA H","SRA L","SRA (I?@o)","SRA A", "SLL B","SLL C","SLL D","SLL E","SLL H","SLL L","SLL (I?@o)","SLL A", "SRL B","SRL C","SRL D","SRL E","SRL H","SRL L","SRL (I?@o)","SRL A", "BIT 0,B","BIT 0,C","BIT 0,D","BIT 0,E","BIT 0,H","BIT 0,L","BIT 0,(I?@o)","BIT 0,A", "BIT 1,B","BIT 1,C","BIT 1,D","BIT 1,E","BIT 1,H","BIT 1,L","BIT 1,(I?@o)","BIT 1,A", "BIT 2,B","BIT 2,C","BIT 2,D","BIT 2,E","BIT 2,H","BIT 2,L","BIT 2,(I?@o)","BIT 2,A", "BIT 3,B","BIT 3,C","BIT 3,D","BIT 3,E","BIT 3,H","BIT 3,L","BIT 3,(I?@o)","BIT 3,A", "BIT 4,B","BIT 4,C","BIT 4,D","BIT 4,E","BIT 4,H","BIT 4,L","BIT 4,(I?@o)","BIT 4,A", "BIT 5,B","BIT 5,C","BIT 5,D","BIT 5,E","BIT 5,H","BIT 5,L","BIT 5,(I?@o)","BIT 5,A", "BIT 6,B","BIT 6,C","BIT 6,D","BIT 6,E","BIT 6,H","BIT 6,L","BIT 6,(I?@o)","BIT 6,A", "BIT 7,B","BIT 7,C","BIT 7,D","BIT 7,E","BIT 7,H","BIT 7,L","BIT 7,(I?@o)","BIT 7,A", "RES 0,B","RES 0,C","RES 0,D","RES 0,E","RES 0,H","RES 0,L","RES 0,(I?@o)","RES 0,A", "RES 1,B","RES 1,C","RES 1,D","RES 1,E","RES 1,H","RES 1,L","RES 1,(I?@o)","RES 1,A", "RES 2,B","RES 2,C","RES 2,D","RES 2,E","RES 2,H","RES 2,L","RES 2,(I?@o)","RES 2,A", "RES 3,B","RES 3,C","RES 3,D","RES 3,E","RES 3,H","RES 3,L","RES 3,(I?@o)","RES 3,A", "RES 4,B","RES 4,C","RES 4,D","RES 4,E","RES 4,H","RES 4,L","RES 4,(I?@o)","RES 4,A", "RES 5,B","RES 5,C","RES 5,D","RES 5,E","RES 5,H","RES 5,L","RES 5,(I?@o)","RES 5,A", "RES 6,B","RES 6,C","RES 6,D","RES 6,E","RES 6,H","RES 6,L","RES 6,(I?@o)","RES 6,A", "RES 7,B","RES 7,C","RES 7,D","RES 7,E","RES 7,H","RES 7,L","RES 7,(I?@o)","RES 7,A", "SET 0,B","SET 0,C","SET 0,D","SET 0,E","SET 0,H","SET 0,L","SET 0,(I?@o)","SET 0,A", "SET 1,B","SET 1,C","SET 1,D","SET 1,E","SET 1,H","SET 1,L","SET 1,(I?@o)","SET 1,A", "SET 2,B","SET 2,C","SET 2,D","SET 2,E","SET 2,H","SET 2,L","SET 2,(I?@o)","SET 2,A", "SET 3,B","SET 3,C","SET 3,D","SET 3,E","SET 3,H","SET 3,L","SET 3,(I?@o)","SET 3,A", "SET 4,B","SET 4,C","SET 4,D","SET 4,E","SET 4,H","SET 4,L","SET 4,(I?@o)","SET 4,A", "SET 5,B","SET 5,C","SET 5,D","SET 5,E","SET 5,H","SET 5,L","SET 5,(I?@o)","SET 5,A", "SET 6,B","SET 6,C","SET 6,D","SET 6,E","SET 6,H","SET 6,L","SET 6,(I?@o)","SET 6,A", "SET 7,B","SET 7,C","SET 7,D","SET 7,E","SET 7,H","SET 7,L","SET 7,(I?@o)","SET 7,A" } }; UINT8 CZ80Debug::ReadReg8(CCPUDebug *cpu, unsigned reg8) { return ((CZ80Debug*)cpu)->m_z80->GetReg8(reg8); } bool CZ80Debug::WriteReg8(CCPUDebug *cpu, unsigned reg8, UINT8 value) { return ((CZ80Debug*)cpu)->m_z80->SetReg8(reg8, value); } UINT16 CZ80Debug::ReadReg16(CCPUDebug *cpu, unsigned reg16) { return ((CZ80Debug*)cpu)->m_z80->GetReg16(reg16); } bool CZ80Debug::WriteReg16(CCPUDebug *cpu, unsigned reg16, UINT16 value) { return ((CZ80Debug*)cpu)->m_z80->SetReg16(reg16, value); } static const char *crGroup = "Control Regs"; static const char *irGroup = "Int/Refresh Regs"; static const char *r8Group = "8-Bit Regs"; static const char *r16Group = "16-Bit Regs"; static const char *srGroup = "Shadow Regs"; CZ80Debug::CZ80Debug(const char *name, CZ80 *z80) : CCPUDebug("Z80", name, 1, 4, false, 16, 4), m_z80(z80) { // Main registers AddPCRegister ("PC", crGroup); AddInt16Register ("SP", crGroup, Z80_REG16_SP, ReadReg16, WriteReg16); AddStatus8Register("F", crGroup, Z80_REG8_F, "SZ.HPVNC", ReadReg8, WriteReg8); AddStatus8Register("IFF", irGroup, Z80_REG8_IFF, "H.E.G21F", ReadReg8, WriteReg8); AddInt8Register ("I", irGroup, Z80_REG8_I, ReadReg8, WriteReg8); AddInt8Register ("R", irGroup, Z80_REG8_R, ReadReg8, WriteReg8); AddInt8Register("A", r8Group, Z80_REG8_A, ReadReg8, WriteReg8); AddInt8Register("B", r8Group, Z80_REG8_B, ReadReg8, WriteReg8); AddInt8Register("C", r8Group, Z80_REG8_C, ReadReg8, WriteReg8); AddInt8Register("D", r8Group, Z80_REG8_D, ReadReg8, WriteReg8); AddInt8Register("E", r8Group, Z80_REG8_E, ReadReg8, WriteReg8); AddInt16Register("AF", r16Group, Z80_REG16_AF, ReadReg16, WriteReg16); AddInt16Register("BC", r16Group, Z80_REG16_BC, ReadReg16, WriteReg16); AddInt16Register("DE", r16Group, Z80_REG16_DE, ReadReg16, WriteReg16); AddInt16Register("HL", r16Group, Z80_REG16_HL, ReadReg16, WriteReg16); AddInt16Register("IX", r16Group, Z80_REG16_IX, ReadReg16, WriteReg16); AddInt16Register("IY", r16Group, Z80_REG16_IY, ReadReg16, WriteReg16); AddInt16Register("AF'", srGroup, Z80_REG16_AF_, ReadReg16, WriteReg16); AddInt16Register("BC'", srGroup, Z80_REG16_BC_, ReadReg16, WriteReg16); AddInt16Register("DE'", srGroup, Z80_REG16_DE_, ReadReg16, WriteReg16); AddInt16Register("HL'", srGroup, Z80_REG16_HL_, ReadReg16, WriteReg16); // Exceptions AddException("NMI", Z80_EX_NMI, "Non-Maskable Interrupt"); AddException("RST00", Z80_INT_RST_00, "RST 00h (IM0)"); AddException("RST08", Z80_INT_RST_08, "RST 08h (IM0)"); AddException("RST10", Z80_INT_RST_10, "RST 10h (IM0)"); AddException("RST18", Z80_INT_RST_18, "RST 18h (IM0)"); AddException("RST20", Z80_INT_RST_20, "RST 20h (IM0)"); AddException("RST28", Z80_INT_RST_28, "RST 28h (IM0)"); AddException("RST30", Z80_INT_RST_30, "RST 30h (IM0)"); AddException("RST38", Z80_INT_RST_38, "RST 38h (IM0)"); AddException("IRQ", Z80_IM1_IRQ, "Hardwired IRQ (IM1)"); AddException("VECTOR", Z80_IM2_VECTOR, "Interrupt Vectors (IM2)"); // Interrupts for (unsigned vecNum = 0; vecNum < 256; vecNum++) { sprintf(m_vecIds[vecNum], "V%u", vecNum + 1); sprintf(m_vecNames[vecNum], "Interrupt Vector #%u", vecNum + 1); AddInterrupt(m_vecIds[vecNum], vecNum, m_vecNames[vecNum]); } // I/O ports for (unsigned portNum = 0; portNum < 256; portNum++) { sprintf(m_portNames[portNum], "Port #%u", portNum); AddPortIO(portNum, 1, m_portNames[portNum], "I/O Ports"); } } CZ80Debug::~CZ80Debug() { DetachFromCPU(); } void CZ80Debug::AttachToCPU() { m_z80->AttachDebugger(this); } ::IBus *CZ80Debug::AttachBus(::IBus *bus) { m_bus = bus; return this; } void CZ80Debug::DetachFromCPU() { m_z80->DetachDebugger(); } ::IBus *CZ80Debug::DetachBus() { ::IBus *bus = m_bus; m_bus = NULL; return bus; } UINT32 CZ80Debug::GetResetAddr() { return 0x0000; } bool CZ80Debug::UpdatePC(UINT32 pc) { return m_z80->SetReg16(Z80_REG16_PC, pc); } bool CZ80Debug::ForceException(CException *ex) { if (ex->code != Z80_EX_NMI) { // TODO return false; } m_z80->TriggerNMI(); return true; } bool CZ80Debug::ForceInterrupt(CInterrupt *in) { // TODO return false; } UINT64 CZ80Debug::ReadMem(UINT32 addr, unsigned dataSize) { if (dataSize == 1) return m_bus->Read8(addr); // TODO - byte swapping return CCPUDebug::ReadMem(addr, dataSize); } bool CZ80Debug::WriteMem(UINT32 addr, unsigned dataSize, UINT64 data) { if (dataSize == 1) { m_bus->Write8(addr, (UINT8)data); return true; } // TODO - byte swapping return CCPUDebug::WriteMem(addr, dataSize, data); } UINT64 CZ80Debug::ReadPort(UINT16 portNum) { return m_bus->IORead8(portNum); } bool CZ80Debug::WritePort(UINT16 portNum, UINT64 data) { m_bus->IOWrite8(portNum, (UINT8)data); return true; } int CZ80Debug::Disassemble(UINT32 addr, char *mnemonic, char *operands) { char tmpStr[128], valStr[50], *templ, *pos; INT8 offs; EOpFlags opFlags; UINT16 dAddr = addr; UINT16 tAddr; char xyChr = '\0'; bool notJump = false; // Get instruction template from opcode UINT8 opcode = m_bus->Read8(dAddr++); UINT8 nextCode; switch (opcode) { case 0xCB: templ = templates[1][m_bus->Read8(dAddr++)]; break; case 0xED: templ = templates[2][m_bus->Read8(dAddr++)]; break; case 0xDD: xyChr = 'X'; nextCode = m_bus->Read8(dAddr++); if (nextCode == 0xCB) { offs = m_bus->Read8(dAddr++); notJump = true; templ = templates[4][m_bus->Read8(dAddr++)]; } else templ = templates[3][nextCode]; break; case 0xFD: xyChr = 'Y'; nextCode = m_bus->Read8(dAddr++); if (nextCode == 0xCB) { offs = m_bus->Read8(dAddr++); notJump = true; templ = templates[4][m_bus->Read8(dAddr++)]; } else templ = templates[3][nextCode]; break; default: templ = templates[0][opcode]; break; } // If no template found, then instruction is invalid if (templ == NULL) return -1; // See if instruction has any operands if (pos = strchr(templ, ' ')) { // If so, substitute all @ parameters in template operand strncpy(mnemonic, templ, pos - templ); mnemonic[pos - templ] = '\0'; operands[0] = '\0'; char *opPos = operands; templ = pos + 1; for (;;) { if (pos = strchr(templ, '@')) { strncpy(opPos, templ, pos - templ); opPos[pos - templ] = '\0'; // Format data for parameter switch (*(pos + 1)) { case 'd': // ^h or *h FormatData(valStr, 1, m_bus->Read8(dAddr++)); break; case 'p': // *p FormatPortNum(valStr, m_bus->Read8(dAddr++), true); break; case 'b': // @H offs = m_bus->Read8(dAddr++); tAddr = dAddr + offs; opFlags = GetOpFlags(addr, opcode); FormatJumpAddress(valStr, tAddr, opFlags); break; case 'o': // @h if (notJump) { // Keep argument as +/-offs strcat(operands, (offs&0x80 ? "-" : "+")); FormatData(valStr, 1, (offs&0x80 ? 256 - offs : offs)); } else { offs = m_bus->Read8(dAddr++); tAddr = dAddr + offs; FormatAddress(valStr, tAddr, true); } break; case 'j': // #H tAddr = m_bus->Read8(dAddr++); tAddr += m_bus->Read8(dAddr++) << 8; opFlags = GetOpFlags(addr, opcode); FormatJumpAddress(valStr, tAddr, opFlags); break; case 'a': // #h tAddr = m_bus->Read8(dAddr++); tAddr += m_bus->Read8(dAddr++) << 8; FormatAddress(valStr, tAddr, true); break; } // Append formatted data and loop again to process any more @ parameters strcat(opPos, valStr); templ = pos + 2; opPos += strlen(opPos); } else { // No more @ parameters found so append remainder of template operand and exit loop strcat(opPos, templ); break; } } // Finally substitute ? parameter (X or Y) if (pos = strchr(operands, '?')) *pos = xyChr; } else { // Instruction has no operands strcpy(mnemonic, templ); operands[0] = '\0'; } // Return instruction size return dAddr - addr; } //int CZ80Debug::GetOpLength(UINT32 addr) //{ // // Get instruction template from opcode // UINT32 dAddr = addr; // UINT8 opcode = m_bus->Read8(dAddr++); // const char *templ; // switch (opcode) // { // case 0xCB: // templ = templates[1][m_bus->Read8(dAddr++)]; // break; // case 0xED: // templ = templates[2][m_bus->Read8(dAddr++)]; // break; // case 0xDD: // opcode = m_bus->Read8(dAddr++); // if (opcode == 0xCB) // { // dAddr++; // templ = templates[4][m_bus->Read8(dAddr++)]; // } // else // templ = templates[3][opcode]; // break; // case 0xFD: // opcode = m_bus->Read8(dAddr++); // if (opcode == 0xCB) // { // dAddr++; // templ = templates[4][m_bus->Read8(dAddr++)]; // } // else // templ = templates[3][opcode]; // break; // default: // templ = templates[0][opcode]; // break; // } // // // If no template found, then instruction is invalid // if (templ == NULL) // return -1; // // // Return instruction size // return dAddr - addr; //} EOpFlags CZ80Debug::GetOpFlags(UINT32 addr, UINT32 opcode) { if (opcode == 0xC3) return JumpSimple; // JP else if (opcode == 0xC2 || opcode == 0xCA || opcode == 0xD2 || opcode == 0xDA || opcode == 0xE2 || opcode == 0xEA || opcode == 0xF2 || opcode == 0xFA) return (EOpFlags)(JumpSimple | Conditional); // JP NZ, JP Z, JP NC, JP C, JP PO, JP PE, JP P, JP M else if (opcode == 0x18) return (EOpFlags)(JumpSimple | Relative); // JR else if (opcode == 0x20 || opcode == 0x28 || opcode == 0x30 || opcode == 0x38) return (EOpFlags)(JumpSimple | Relative | Conditional); // JR NZ, JR Z, JR NC, JR C else if (opcode == 0x10) return (EOpFlags)(JumpLoop | Relative | Conditional); // DJNZ else if (opcode == 0xCD) return JumpSub; // CALL else if (opcode == 0xC4 || opcode == 0xCC || opcode == 0xD4 || opcode == 0xDC || opcode == 0xE4 || opcode == 0xEC || opcode == 0xF4 || opcode == 0xFC) return (EOpFlags)(JumpSub | Conditional); // CALL NZ, CALL Z, CALL NC, CALL C, CALL PO, CALL PE, CALL P, CALL M else if (opcode == 0xC9) return ReturnSub; // RET else if (opcode == 0xC0 || opcode == 0xC8 || opcode == 0xD0 || opcode == 0xD8 || opcode == 0xE0 || opcode == 0xE8 || opcode == 0xF0 || opcode == 0xF8) return (EOpFlags)(ReturnSub | Conditional); // RET NZ, RET Z, RET NC, RET C, RET PO, RET PE, RET P, RET M else if (opcode == 0xC7 || opcode == 0xCF || opcode == 0xD7 || opcode == 0xD7 || opcode == 0xE7 || opcode == 0xEF || opcode == 0xF7 || opcode == 0xFF) return (EOpFlags)(JumpEx | NotFixed); // RST 0, RST 8, RST 10H, RST 18H, RST 20H, RST 28H, RST 30H, RST 38H else if (opcode == 0xED) { UINT8 nextCode = m_bus->Read8(addr + 1); if (nextCode == 0x4D || nextCode == 0x45) return ReturnEx; // RETI, RETN } else if (opcode == 0xE9 || opcode == 0xDD && m_bus->Read8(addr + 1) == 0xE9 || opcode == 0xFD && m_bus->Read8(addr + 1) == 0xE9) return (EOpFlags)(JumpSimple | NotFixed); // JR (HL), JR (IX) or JR (IY) return NormalOp; } bool CZ80Debug::GetJumpAddr(UINT32 addr, UINT32 opcode, UINT32 &jumpAddr) { if (opcode == 0xC3 || opcode == 0xC2 || opcode == 0xCA || opcode == 0xD2 || opcode == 0xDA || opcode == 0xE2 || opcode == 0xEA || opcode == 0xF2 || opcode == 0xFA || opcode == 0xCD || opcode == 0xC4 || opcode == 0xCC || opcode == 0xD4 || opcode == 0xDC || opcode == 0xE4 || opcode == 0xEC || opcode == 0xF4 || opcode == 0xFC) { // JP, JP NZ, JP Z, JP NC, JP C, JP PO, JP PE, JP P, JP M, // CALL, CALL NZ, CALL Z, CALL NC, CALL C, CALL PO, CALL PE, CALL P, CALL M jumpAddr = (UINT32)(m_bus->Read8(addr + 1) + (m_bus->Read8(addr + 2)<<8)); return true; } else if (opcode == 0x18 || opcode == 0x20 || opcode == 0x28 || opcode == 0x30 || opcode == 0x38 || opcode == 0x10) { // JR, JR NZ, JR NC, JR C, DJNZ INT8 offs = m_bus->Read8(addr + 1); jumpAddr = addr + 2 + offs; return true; } return false; } bool CZ80Debug::GetJumpRetAddr(UINT32 addr, UINT32 opcode, UINT32 &retAddr) { if (opcode == 0xCD || opcode == 0xC4 || opcode == 0xCC || opcode == 0xD4 || opcode == 0xDC || opcode == 0xE4 || opcode == 0xEC || opcode == 0xF4 || opcode == 0xFC) { // CALL, CALL NZ, CALL Z, CALL NC, CALL C, CALL PO, CALL PE, CALL P, CALL M retAddr = addr + 3; return true; } else if (opcode == 0xC7 || opcode == 0xCF || opcode == 0xD7 || opcode == 0xD7 || opcode == 0xE7 || opcode == 0xEF || opcode == 0xF7 || opcode == 0xFF) { // RST 0, RST 8, RST 10H, RST 18H, RST 20H, RST 28H, RST 30H, RST 38H retAddr = addr + 1; } return false; } bool CZ80Debug::GetReturnAddr(UINT32 addr, UINT32 opcode, UINT32 &retAddr) { if (opcode == 0xC9 || opcode == 0xC0 || opcode == 0xC8 || opcode == 0xD0 || opcode == 0xD8 || opcode == 0xE0 || opcode == 0xE8 || opcode == 0xF0 || opcode == 0xF8) { // RET, RET NZ, RET Z, RET NC, RET C, RET PO, RET PE, RET P, RET M UINT16 sp = m_z80->GetReg16(Z80_REG16_SP); retAddr = (UINT32)m_bus->Read8(sp) + (((UINT32)m_bus->Read8(sp + 1))<<8); return true; } else if (opcode == 0xED) { UINT8 nextCode = m_bus->Read8(addr + 1); if (nextCode == 0x4D || nextCode == 0x45) { // RETI, RETN UINT16 sp = m_z80->GetReg16(Z80_REG16_SP); retAddr = (UINT32)m_bus->Read8(sp) + (((UINT32)m_bus->Read8(sp + 1))<<8); return true; } } return false; } bool CZ80Debug::GetHandlerAddr(CException *ex, UINT32 &handlerAddr) { switch (ex->code) { case Z80_EX_NMI: handlerAddr = 0x0066; return true; // Hardwired NMI vector case Z80_INT_RST_00: handlerAddr = 0x0000; return true; // RST 0h case Z80_INT_RST_08: handlerAddr = 0x0008; return true; // RST 8h case Z80_INT_RST_10: handlerAddr = 0x0010; return true; // RST 10h case Z80_INT_RST_18: handlerAddr = 0x0018; return true; // RST 18h case Z80_INT_RST_20: handlerAddr = 0x0020; return true; // RST 20h case Z80_INT_RST_28: handlerAddr = 0x0028; return true; // RST 28h case Z80_INT_RST_30: handlerAddr = 0x0030; return true; // RST 30h case Z80_INT_RST_38: handlerAddr = 0x0038; return true; // RST 38h case Z80_IM1_IRQ: handlerAddr = 0x0038; return true; // Hardwired IRQ vector default: return false; } } bool CZ80Debug::GetHandlerAddr(CInterrupt *in, UINT32 &handlerAddr) { UINT8 iff = m_z80->GetReg8(Z80_REG8_IFF); if (!(iff&0x04)) // IM2 mode return false; UINT8 i = m_z80->GetReg8(Z80_REG8_I); handlerAddr = (((UINT32)i)<<8)|(((UINT32)in->code)&0xFF); return true; } // IBus methods UINT8 CZ80Debug::Read8(UINT32 addr) { UINT8 data = m_bus->Read8(addr); CheckRead8(addr, data); return data; } void CZ80Debug::Write8(UINT32 addr, UINT8 data) { m_bus->Write8(addr, data); CheckWrite8(addr, data); } UINT8 CZ80Debug::IORead8(UINT32 portNum) { UINT8 data = m_bus->IORead8(portNum); CheckPortInput(portNum, data); return data; } void CZ80Debug::IOWrite8(UINT32 portNum, UINT8 data) { m_bus->IOWrite8(portNum, data); CheckPortOutput(portNum, data); } } #endif // SUPERMODEL_DEBUGGER