/* Z80 emulator Copyright (c) 1996-2003,2004 Alessandro Scotti http://www.ascotti.org/ This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "z80.h" Z80::OpcodeInfo Z80::OpInfo_[256] = { { &Z80::opcode_00, 4 }, // NOP { &Z80::opcode_01, 10 }, // LD BC,nn { &Z80::opcode_02, 7 }, // LD (BC),A { &Z80::opcode_03, 6 }, // INC BC { &Z80::opcode_04, 4 }, // INC B { &Z80::opcode_05, 4 }, // DEC B { &Z80::opcode_06, 7 }, // LD B,n { &Z80::opcode_07, 4 }, // RLCA { &Z80::opcode_08, 4 }, // EX AF,AF' { &Z80::opcode_09, 11 }, // ADD HL,BC { &Z80::opcode_0a, 7 }, // LD A,(BC) { &Z80::opcode_0b, 6 }, // DEC BC { &Z80::opcode_0c, 4 }, // INC C { &Z80::opcode_0d, 4 }, // DEC C { &Z80::opcode_0e, 7 }, // LD C,n { &Z80::opcode_0f, 4 }, // RRCA { &Z80::opcode_10, 8 }, // DJNZ d { &Z80::opcode_11, 10 }, // LD DE,nn { &Z80::opcode_12, 7 }, // LD (DE),A { &Z80::opcode_13, 6 }, // INC DE { &Z80::opcode_14, 4 }, // INC D { &Z80::opcode_15, 4 }, // DEC D { &Z80::opcode_16, 7 }, // LD D,n { &Z80::opcode_17, 4 }, // RLA { &Z80::opcode_18, 12 }, // JR d { &Z80::opcode_19, 11 }, // ADD HL,DE { &Z80::opcode_1a, 7 }, // LD A,(DE) { &Z80::opcode_1b, 6 }, // DEC DE { &Z80::opcode_1c, 4 }, // INC E { &Z80::opcode_1d, 4 }, // DEC E { &Z80::opcode_1e, 7 }, // LD E,n { &Z80::opcode_1f, 4 }, // RRA { &Z80::opcode_20, 7 }, // JR NZ,d { &Z80::opcode_21, 10 }, // LD HL,nn { &Z80::opcode_22, 16 }, // LD (nn),HL { &Z80::opcode_23, 6 }, // INC HL { &Z80::opcode_24, 4 }, // INC H { &Z80::opcode_25, 4 }, // DEC H { &Z80::opcode_26, 7 }, // LD H,n { &Z80::opcode_27, 4 }, // DAA { &Z80::opcode_28, 7 }, // JR Z,d { &Z80::opcode_29, 11 }, // ADD HL,HL { &Z80::opcode_2a, 16 }, // LD HL,(nn) { &Z80::opcode_2b, 6 }, // DEC HL { &Z80::opcode_2c, 4 }, // INC L { &Z80::opcode_2d, 4 }, // DEC L { &Z80::opcode_2e, 7 }, // LD L,n { &Z80::opcode_2f, 4 }, // CPL { &Z80::opcode_30, 7 }, // JR NC,d { &Z80::opcode_31, 10 }, // LD SP,nn { &Z80::opcode_32, 13 }, // LD (nn),A { &Z80::opcode_33, 6 }, // INC SP { &Z80::opcode_34, 11 }, // INC (HL) { &Z80::opcode_35, 11 }, // DEC (HL) { &Z80::opcode_36, 10 }, // LD (HL),n { &Z80::opcode_37, 4 }, // SCF { &Z80::opcode_38, 7 }, // JR C,d { &Z80::opcode_39, 11 }, // ADD HL,SP { &Z80::opcode_3a, 13 }, // LD A,(nn) { &Z80::opcode_3b, 6 }, // DEC SP { &Z80::opcode_3c, 4 }, // INC A { &Z80::opcode_3d, 4 }, // DEC A { &Z80::opcode_3e, 7 }, // LD A,n { &Z80::opcode_3f, 4 }, // CCF { &Z80::opcode_40, 4 }, // LD B,B { &Z80::opcode_41, 4 }, // LD B,C { &Z80::opcode_42, 4 }, // LD B,D { &Z80::opcode_43, 4 }, // LD B,E { &Z80::opcode_44, 4 }, // LD B,H { &Z80::opcode_45, 4 }, // LD B,L { &Z80::opcode_46, 7 }, // LD B,(HL) { &Z80::opcode_47, 4 }, // LD B,A { &Z80::opcode_48, 4 }, // LD C,B { &Z80::opcode_49, 4 }, // LD C,C { &Z80::opcode_4a, 4 }, // LD C,D { &Z80::opcode_4b, 4 }, // LD C,E { &Z80::opcode_4c, 4 }, // LD C,H { &Z80::opcode_4d, 4 }, // LD C,L { &Z80::opcode_4e, 7 }, // LD C,(HL) { &Z80::opcode_4f, 4 }, // LD C,A { &Z80::opcode_50, 4 }, // LD D,B { &Z80::opcode_51, 4 }, // LD D,C { &Z80::opcode_52, 4 }, // LD D,D { &Z80::opcode_53, 4 }, // LD D,E { &Z80::opcode_54, 4 }, // LD D,H { &Z80::opcode_55, 4 }, // LD D,L { &Z80::opcode_56, 7 }, // LD D,(HL) { &Z80::opcode_57, 4 }, // LD D,A { &Z80::opcode_58, 4 }, // LD E,B { &Z80::opcode_59, 4 }, // LD E,C { &Z80::opcode_5a, 4 }, // LD E,D { &Z80::opcode_5b, 4 }, // LD E,E { &Z80::opcode_5c, 4 }, // LD E,H { &Z80::opcode_5d, 4 }, // LD E,L { &Z80::opcode_5e, 7 }, // LD E,(HL) { &Z80::opcode_5f, 4 }, // LD E,A { &Z80::opcode_60, 4 }, // LD H,B { &Z80::opcode_61, 4 }, // LD H,C { &Z80::opcode_62, 4 }, // LD H,D { &Z80::opcode_63, 4 }, // LD H,E { &Z80::opcode_64, 4 }, // LD H,H { &Z80::opcode_65, 4 }, // LD H,L { &Z80::opcode_66, 7 }, // LD H,(HL) { &Z80::opcode_67, 4 }, // LD H,A { &Z80::opcode_68, 4 }, // LD L,B { &Z80::opcode_69, 4 }, // LD L,C { &Z80::opcode_6a, 4 }, // LD L,D { &Z80::opcode_6b, 4 }, // LD L,E { &Z80::opcode_6c, 4 }, // LD L,H { &Z80::opcode_6d, 4 }, // LD L,L { &Z80::opcode_6e, 7 }, // LD L,(HL) { &Z80::opcode_6f, 4 }, // LD L,A { &Z80::opcode_70, 7 }, // LD (HL),B { &Z80::opcode_71, 7 }, // LD (HL),C { &Z80::opcode_72, 7 }, // LD (HL),D { &Z80::opcode_73, 7 }, // LD (HL),E { &Z80::opcode_74, 7 }, // LD (HL),H { &Z80::opcode_75, 7 }, // LD (HL),L { &Z80::opcode_76, 4 }, // HALT { &Z80::opcode_77, 7 }, // LD (HL),A { &Z80::opcode_78, 4 }, // LD A,B { &Z80::opcode_79, 4 }, // LD A,C { &Z80::opcode_7a, 4 }, // LD A,D { &Z80::opcode_7b, 4 }, // LD A,E { &Z80::opcode_7c, 4 }, // LD A,H { &Z80::opcode_7d, 4 }, // LD A,L { &Z80::opcode_7e, 7 }, // LD A,(HL) { &Z80::opcode_7f, 4 }, // LD A,A { &Z80::opcode_80, 4 }, // ADD A,B { &Z80::opcode_81, 4 }, // ADD A,C { &Z80::opcode_82, 4 }, // ADD A,D { &Z80::opcode_83, 4 }, // ADD A,E { &Z80::opcode_84, 4 }, // ADD A,H { &Z80::opcode_85, 4 }, // ADD A,L { &Z80::opcode_86, 7 }, // ADD A,(HL) { &Z80::opcode_87, 4 }, // ADD A,A { &Z80::opcode_88, 4 }, // ADC A,B { &Z80::opcode_89, 4 }, // ADC A,C { &Z80::opcode_8a, 4 }, // ADC A,D { &Z80::opcode_8b, 4 }, // ADC A,E { &Z80::opcode_8c, 4 }, // ADC A,H { &Z80::opcode_8d, 4 }, // ADC A,L { &Z80::opcode_8e, 7 }, // ADC A,(HL) { &Z80::opcode_8f, 4 }, // ADC A,A { &Z80::opcode_90, 4 }, // SUB B { &Z80::opcode_91, 4 }, // SUB C { &Z80::opcode_92, 4 }, // SUB D { &Z80::opcode_93, 4 }, // SUB E { &Z80::opcode_94, 4 }, // SUB H { &Z80::opcode_95, 4 }, // SUB L { &Z80::opcode_96, 7 }, // SUB (HL) { &Z80::opcode_97, 4 }, // SUB A { &Z80::opcode_98, 4 }, // SBC A,B { &Z80::opcode_99, 4 }, // SBC A,C { &Z80::opcode_9a, 4 }, // SBC A,D { &Z80::opcode_9b, 4 }, // SBC A,E { &Z80::opcode_9c, 4 }, // SBC A,H { &Z80::opcode_9d, 4 }, // SBC A,L { &Z80::opcode_9e, 7 }, // SBC A,(HL) { &Z80::opcode_9f, 4 }, // SBC A,A { &Z80::opcode_a0, 4 }, // AND B { &Z80::opcode_a1, 4 }, // AND C { &Z80::opcode_a2, 4 }, // AND D { &Z80::opcode_a3, 4 }, // AND E { &Z80::opcode_a4, 4 }, // AND H { &Z80::opcode_a5, 4 }, // AND L { &Z80::opcode_a6, 7 }, // AND (HL) { &Z80::opcode_a7, 4 }, // AND A { &Z80::opcode_a8, 4 }, // XOR B { &Z80::opcode_a9, 4 }, // XOR C { &Z80::opcode_aa, 4 }, // XOR D { &Z80::opcode_ab, 4 }, // XOR E { &Z80::opcode_ac, 4 }, // XOR H { &Z80::opcode_ad, 4 }, // XOR L { &Z80::opcode_ae, 7 }, // XOR (HL) { &Z80::opcode_af, 4 }, // XOR A { &Z80::opcode_b0, 4 }, // OR B { &Z80::opcode_b1, 4 }, // OR C { &Z80::opcode_b2, 4 }, // OR D { &Z80::opcode_b3, 4 }, // OR E { &Z80::opcode_b4, 4 }, // OR H { &Z80::opcode_b5, 4 }, // OR L { &Z80::opcode_b6, 7 }, // OR (HL) { &Z80::opcode_b7, 4 }, // OR A { &Z80::opcode_b8, 4 }, // CP B { &Z80::opcode_b9, 4 }, // CP C { &Z80::opcode_ba, 4 }, // CP D { &Z80::opcode_bb, 4 }, // CP E { &Z80::opcode_bc, 4 }, // CP H { &Z80::opcode_bd, 4 }, // CP L { &Z80::opcode_be, 7 }, // CP (HL) { &Z80::opcode_bf, 4 }, // CP A { &Z80::opcode_c0, 5 }, // RET NZ { &Z80::opcode_c1, 10 }, // POP BC { &Z80::opcode_c2, 10 }, // JP NZ,nn { &Z80::opcode_c3, 10 }, // JP nn { &Z80::opcode_c4, 10 }, // CALL NZ,nn { &Z80::opcode_c5, 11 }, // PUSH BC { &Z80::opcode_c6, 7 }, // ADD A,n { &Z80::opcode_c7, 11 }, // RST 0 { &Z80::opcode_c8, 5 }, // RET Z { &Z80::opcode_c9, 10 }, // RET { &Z80::opcode_ca, 10 }, // JP Z,nn { &Z80::opcode_cb, 0 }, // [Prefix] { &Z80::opcode_cc, 10 }, // CALL Z,nn { &Z80::opcode_cd, 17 }, // CALL nn { &Z80::opcode_ce, 7 }, // ADC A,n { &Z80::opcode_cf, 11 }, // RST 8 { &Z80::opcode_d0, 5 }, // RET NC { &Z80::opcode_d1, 10 }, // POP DE { &Z80::opcode_d2, 10 }, // JP NC,nn { &Z80::opcode_d3, 11 }, // OUT (n),A { &Z80::opcode_d4, 10 }, // CALL NC,nn { &Z80::opcode_d5, 11 }, // PUSH DE { &Z80::opcode_d6, 7 }, // SUB n { &Z80::opcode_d7, 11 }, // RST 10H { &Z80::opcode_d8, 5 }, // RET C { &Z80::opcode_d9, 4 }, // EXX { &Z80::opcode_da, 10 }, // JP C,nn { &Z80::opcode_db, 11 }, // IN A,(n) { &Z80::opcode_dc, 10 }, // CALL C,nn { &Z80::opcode_dd, 0 }, // [IX Prefix] { &Z80::opcode_de, 7 }, // SBC A,n { &Z80::opcode_df, 11 }, // RST 18H { &Z80::opcode_e0, 5 }, // RET PO { &Z80::opcode_e1, 10 }, // POP HL { &Z80::opcode_e2, 10 }, // JP PO,nn { &Z80::opcode_e3, 19 }, // EX (SP),HL { &Z80::opcode_e4, 10 }, // CALL PO,nn { &Z80::opcode_e5, 11 }, // PUSH HL { &Z80::opcode_e6, 7 }, // AND n { &Z80::opcode_e7, 11 }, // RST 20H { &Z80::opcode_e8, 5 }, // RET PE { &Z80::opcode_e9, 4 }, // JP (HL) { &Z80::opcode_ea, 10 }, // JP PE,nn { &Z80::opcode_eb, 4 }, // EX DE,HL { &Z80::opcode_ec, 10 }, // CALL PE,nn { &Z80::opcode_ed, 0 }, // [Prefix] { &Z80::opcode_ee, 7 }, // XOR n { &Z80::opcode_ef, 11 }, // RST 28H { &Z80::opcode_f0, 5 }, // RET P { &Z80::opcode_f1, 10 }, // POP AF { &Z80::opcode_f2, 10 }, // JP P,nn { &Z80::opcode_f3, 4 }, // DI { &Z80::opcode_f4, 10 }, // CALL P,nn { &Z80::opcode_f5, 11 }, // PUSH AF { &Z80::opcode_f6, 7 }, // OR n { &Z80::opcode_f7, 11 }, // RST 30H { &Z80::opcode_f8, 5 }, // RET M { &Z80::opcode_f9, 6 }, // LD SP,HL { &Z80::opcode_fa, 10 }, // JP M,nn { &Z80::opcode_fb, 4 }, // EI { &Z80::opcode_fc, 10 }, // CALL M,nn { &Z80::opcode_fd, 0 }, // [IY Prefix] { &Z80::opcode_fe, 7 }, // CP n { &Z80::opcode_ff, 11 } // RST 38H }; void Z80::opcode_00() // NOP { } void Z80::opcode_01() // LD BC,nn { C = fetchByte(); B = fetchByte(); } void Z80::opcode_02() // LD (BC),A { env_.writeByte( BC(), A ); } void Z80::opcode_03() // INC BC { if( ++C == 0 ) ++B; } void Z80::opcode_04() // INC B { B = incByte( B ); } void Z80::opcode_05() // DEC B { B = decByte( B ); } void Z80::opcode_06() // LD B,n { B = fetchByte(); } void Z80::opcode_07() // RLCA { A = (A << 1) | (A >> 7); F = F & ~(AddSub | Halfcarry | Carry); if( A & 0x01 ) F |= Carry; } void Z80::opcode_08() // EX AF,AF' { unsigned char x; x = A; A = A1; A1 = x; x = F; F = F1; F1 = x; } void Z80::opcode_09() // ADD HL,BC { unsigned hl = HL(); unsigned rp = BC(); unsigned x = hl + rp; F &= Sign | Zero | Parity; if( x > 0xFFFF ) F |= Carry; if( ((hl & 0xFFF) + (rp & 0xFFF)) > 0xFFF ) F |= Halfcarry; L = x & 0xFF; H = (x >> 8) & 0xFF; } void Z80::opcode_0a() // LD A,(BC) { A = env_.readByte( BC() ); } void Z80::opcode_0b() // DEC BC { if( C-- == 0 ) --B; } void Z80::opcode_0c() // INC C { C = incByte( C ); } void Z80::opcode_0d() // DEC C { C = decByte( C ); } void Z80::opcode_0e() // LD C,n { C = fetchByte(); } void Z80::opcode_0f() // RRCA { A = (A >> 1) | (A << 7); F = F & ~(AddSub | Halfcarry | Carry); if( A & 0x80 ) F |= Carry; } void Z80::opcode_10() // DJNZ d { unsigned char o = fetchByte(); if( --B != 0 ) relJump( o ); } void Z80::opcode_11() // LD DE,nn { E = fetchByte(); D = fetchByte(); } void Z80::opcode_12() // LD (DE),A { env_.writeByte( DE(), A ); } void Z80::opcode_13() // INC DE { if( ++E == 0 ) ++D; } void Z80::opcode_14() // INC D { D = incByte( D ); } void Z80::opcode_15() // DEC D { D = decByte( D ); } void Z80::opcode_16() // LD D,n { D = fetchByte(); } void Z80::opcode_17() // RLA { unsigned char a = A; A <<= 1; if( F & Carry ) A |= 0x01; F = F & ~(AddSub | Halfcarry | Carry); if( a & 0x80 ) F |= Carry; } void Z80::opcode_18() // JR d { relJump( fetchByte() ); } void Z80::opcode_19() // ADD HL,DE { unsigned hl = HL(); unsigned rp = DE(); unsigned x = hl + rp; F &= Sign | Zero | Parity; if( x > 0xFFFF ) F |= Carry; if( ((hl & 0xFFF) + (rp & 0xFFF)) > 0xFFF ) F |= Halfcarry; L = x & 0xFF; H = (x >> 8) & 0xFF; } void Z80::opcode_1a() // LD A,(DE) { A = env_.readByte( DE() ); } void Z80::opcode_1b() // DEC DE { if( E-- == 0 ) --D; } void Z80::opcode_1c() // INC E { E = incByte( E ); } void Z80::opcode_1d() // DEC E { E = decByte( E ); } void Z80::opcode_1e() // LD E,n { E = fetchByte(); } void Z80::opcode_1f() // RRA { unsigned char a = A; A >>= 1; if( F & Carry ) A |= 0x80; F = F & ~(AddSub | Halfcarry | Carry); if( a & 0x01 ) F |= Carry; } void Z80::opcode_20() // JR NZ,d { unsigned char o = fetchByte(); if( ! (F & Zero) ) relJump( o ); } void Z80::opcode_21() // LD HL,nn { L = fetchByte(); H = fetchByte(); } void Z80::opcode_22() // LD (nn),HL { unsigned x = fetchWord(); env_.writeByte( x , L ); env_.writeByte( x+1, H ); } void Z80::opcode_23() // INC HL { if( ++L == 0 ) ++H; } void Z80::opcode_24() // INC H { H = incByte( H ); } void Z80::opcode_25() // DEC H { H = decByte( H ); } void Z80::opcode_26() // LD H,n { H = fetchByte(); } /* DAA is computed using the following table to get a diff value that is added to or subtracted (according to the N flag) from A: C Upper H Lower Diff -+-----+-+-----+---- 1 * 0 0-9 60 1 * 1 0-9 66 1 * * A-F 66 0 0-9 0 0-9 00 0 0-9 1 0-9 06 0 0-8 * A-F 06 0 A-F 0 0-9 60 0 9-F * A-F 66 0 A-F 1 0-9 66 The carry and halfcarry flags are then updated using similar tables. These tables were found by Stefano Donati of Ramsoft and are published in the "Undocumented Z80 Documented" paper by Sean Young, the following is an algorithmical implementation with no lookups. */ void Z80::opcode_27() // DAA { unsigned char diff; unsigned char hf = F & Halfcarry; unsigned char cf = F & Carry; unsigned char lower = A & 0x0F; if( cf ) { diff = (lower >= 0x0A) || hf ? 0x66 : 0x60; } else { diff = (A >= 0x9A) ? 0x60 : 0x00; if( hf || (lower >= 0x0A) ) diff += 0x06; } if( A >= 0x9A ) cf = Carry; if( F & Subtraction ) { A -= diff; F = PSZ_[A] | Subtraction | cf; if( hf && (lower <= 0x05) ) F |= Halfcarry; } else { A += diff; F = PSZ_[A] | cf; if( lower >= 0x0A ) F |= Halfcarry; } } void Z80::opcode_28() // JR Z,d { unsigned char o = fetchByte(); if( F & Zero ) relJump( o ); } void Z80::opcode_29() // ADD HL,HL { unsigned hl = HL(); unsigned rp = hl; unsigned x = hl + rp; F &= Sign | Zero | Parity; if( x > 0xFFFF ) F |= Carry; if( ((hl & 0xFFF) + (rp & 0xFFF)) > 0xFFF ) F |= Halfcarry; L = x & 0xFF; H = (x >> 8) & 0xFF; } void Z80::opcode_2a() // LD HL,(nn) { unsigned x = fetchWord(); L = env_.readByte( x ); H = env_.readByte( x+1 ); } void Z80::opcode_2b() // DEC HL { if( L-- == 0 ) --H; } void Z80::opcode_2c() // INC L { L = incByte( L ); } void Z80::opcode_2d() // DEC L { L = decByte( L ); } void Z80::opcode_2e() // LD L,n { L = fetchByte(); } void Z80::opcode_2f() // CPL { A ^= 0xFF; F |= AddSub | Halfcarry; } void Z80::opcode_30() // JR NC,d { unsigned char o = fetchByte(); if( ! (F & Carry) ) relJump( o ); } void Z80::opcode_31() // LD SP,nn { SP = fetchWord(); } void Z80::opcode_32() // LD (nn),A { env_.writeByte( fetchWord(), A ); } void Z80::opcode_33() // INC SP { SP = (SP + 1) & 0xFFFF; } void Z80::opcode_34() // INC (HL) { env_.writeByte( HL(), incByte( env_.readByte( HL() ) ) ); } void Z80::opcode_35() // DEC (HL) { env_.writeByte( HL(), decByte( env_.readByte( HL() ) ) ); } void Z80::opcode_36() // LD (HL),n { env_.writeByte( HL(), fetchByte() ); } void Z80::opcode_37() // SCF { F = (F & (Parity | Sign | Zero)) | Carry; } void Z80::opcode_38() // JR C,d { unsigned char o = fetchByte(); if( F & Carry ) relJump( o ); } void Z80::opcode_39() // ADD HL,SP { unsigned hl = HL(); unsigned rp = SP; unsigned x = hl + rp; F &= Sign | Zero | Parity; if( x > 0xFFFF ) F |= Carry; if( ((hl & 0xFFF) + (rp & 0xFFF)) > 0xFFF ) F |= Halfcarry; L = x & 0xFF; H = (x >> 8) & 0xFF; } void Z80::opcode_3a() // LD A,(nn) { A = env_.readByte( fetchWord() ); } void Z80::opcode_3b() // DEC SP { SP = (SP - 1) & 0xFFFF; } void Z80::opcode_3c() // INC A { A = incByte( A ); } void Z80::opcode_3d() // DEC A { A = decByte( A ); } void Z80::opcode_3e() // LD A,n { A = fetchByte(); } void Z80::opcode_3f() // CCF { if( F & Carry ) { F = (F & (Parity | Sign | Zero)) | Halfcarry; // Halfcarry holds previous carry } else { F = (F & (Parity | Sign | Zero)) | Carry; } } void Z80::opcode_40() // LD B,B { } void Z80::opcode_41() // LD B,C { B = C; } void Z80::opcode_42() // LD B,D { B = D; } void Z80::opcode_43() // LD B,E { B = E; } void Z80::opcode_44() // LD B,H { B = H; } void Z80::opcode_45() // LD B,L { B = L; } void Z80::opcode_46() // LD B,(HL) { B = env_.readByte( HL() ); } void Z80::opcode_47() // LD B,A { B = A; } void Z80::opcode_48() // LD C,B { C = B; } void Z80::opcode_49() // LD C,C { } void Z80::opcode_4a() // LD C,D { C = D; } void Z80::opcode_4b() // LD C,E { C = E; } void Z80::opcode_4c() // LD C,H { C = H; } void Z80::opcode_4d() // LD C,L { C = L; } void Z80::opcode_4e() // LD C,(HL) { C = env_.readByte( HL() ); } void Z80::opcode_4f() // LD C,A { C = A; } void Z80::opcode_50() // LD D,B { D = B; } void Z80::opcode_51() // LD D,C { D = C; } void Z80::opcode_52() // LD D,D { } void Z80::opcode_53() // LD D,E { D = E; } void Z80::opcode_54() // LD D,H { D = H; } void Z80::opcode_55() // LD D,L { D = L; } void Z80::opcode_56() // LD D,(HL) { D = env_.readByte( HL() ); } void Z80::opcode_57() // LD D,A { D = A; } void Z80::opcode_58() // LD E,B { E = B; } void Z80::opcode_59() // LD E,C { E = C; } void Z80::opcode_5a() // LD E,D { E = D; } void Z80::opcode_5b() // LD E,E { } void Z80::opcode_5c() // LD E,H { E = H; } void Z80::opcode_5d() // LD E,L { E = L; } void Z80::opcode_5e() // LD E,(HL) { E = env_.readByte( HL() ); } void Z80::opcode_5f() // LD E,A { E = A; } void Z80::opcode_60() // LD H,B { H = B; } void Z80::opcode_61() // LD H,C { H = C; } void Z80::opcode_62() // LD H,D { H = D; } void Z80::opcode_63() // LD H,E { H = E; } void Z80::opcode_64() // LD H,H { } void Z80::opcode_65() // LD H,L { H = L; } void Z80::opcode_66() // LD H,(HL) { H = env_.readByte( HL() ); } void Z80::opcode_67() // LD H,A { H = A; } void Z80::opcode_68() // LD L,B { L = B; } void Z80::opcode_69() // LD L,C { L = C; } void Z80::opcode_6a() // LD L,D { L = D; } void Z80::opcode_6b() // LD L,E { L = E; } void Z80::opcode_6c() // LD L,H { L = H; } void Z80::opcode_6d() // LD L,L { } void Z80::opcode_6e() // LD L,(HL) { L = env_.readByte( HL() ); } void Z80::opcode_6f() // LD L,A { L = A; } void Z80::opcode_70() // LD (HL),B { env_.writeByte( HL(), B ); } void Z80::opcode_71() // LD (HL),C { env_.writeByte( HL(), C ); } void Z80::opcode_72() // LD (HL),D { env_.writeByte( HL(), D ); } void Z80::opcode_73() // LD (HL),E { env_.writeByte( HL(), E ); } void Z80::opcode_74() // LD (HL),H { env_.writeByte( HL(), H ); } void Z80::opcode_75() // LD (HL),L { env_.writeByte( HL(), L ); } void Z80::opcode_76() // HALT { iflags_ |= Halted; } void Z80::opcode_77() // LD (HL),A { env_.writeByte( HL(), A ); } void Z80::opcode_78() // LD A,B { A = B; } void Z80::opcode_79() // LD A,C { A = C; } void Z80::opcode_7a() // LD A,D { A = D; } void Z80::opcode_7b() // LD A,E { A = E; } void Z80::opcode_7c() // LD A,H { A = H; } void Z80::opcode_7d() // LD A,L { A = L; } void Z80::opcode_7e() // LD A,(HL) { A = env_.readByte( HL() ); } void Z80::opcode_7f() // LD A,A { } void Z80::opcode_80() // ADD A,B { addByte( B, 0 ); } void Z80::opcode_81() // ADD A,C { addByte( C, 0 ); } void Z80::opcode_82() // ADD A,D { addByte( D, 0 ); } void Z80::opcode_83() // ADD A,E { addByte( E, 0 ); } void Z80::opcode_84() // ADD A,H { addByte( H, 0 ); } void Z80::opcode_85() // ADD A,L { addByte( L, 0 ); } void Z80::opcode_86() // ADD A,(HL) { addByte( env_.readByte( HL() ), 0 ); } void Z80::opcode_87() // ADD A,A { addByte( A, 0 ); } void Z80::opcode_88() // ADC A,B { addByte( B, F & Carry ); } void Z80::opcode_89() // ADC A,C { addByte( C, F & Carry ); } void Z80::opcode_8a() // ADC A,D { addByte( D, F & Carry ); } void Z80::opcode_8b() // ADC A,E { addByte( E, F & Carry ); } void Z80::opcode_8c() // ADC A,H { addByte( H, F & Carry ); } void Z80::opcode_8d() // ADC A,L { addByte( L, F & Carry ); } void Z80::opcode_8e() // ADC A,(HL) { addByte( env_.readByte( HL() ), F & Carry ); } void Z80::opcode_8f() // ADC A,A { addByte( A, F & Carry ); } void Z80::opcode_90() // SUB B { A = subByte( B, 0 ); } void Z80::opcode_91() // SUB C { A = subByte( C, 0 ); } void Z80::opcode_92() // SUB D { A = subByte( D, 0 ); } void Z80::opcode_93() // SUB E { A = subByte( E, 0 ); } void Z80::opcode_94() // SUB H { A = subByte( H, 0 ); } void Z80::opcode_95() // SUB L { A = subByte( L, 0 ); } void Z80::opcode_96() // SUB (HL) { A = subByte( env_.readByte( HL() ), 0 ); } void Z80::opcode_97() // SUB A { A = subByte( A, 0 ); } void Z80::opcode_98() // SBC A,B { A = subByte( B, F & Carry ); } void Z80::opcode_99() // SBC A,C { A = subByte( C, F & Carry ); } void Z80::opcode_9a() // SBC A,D { A = subByte( D, F & Carry ); } void Z80::opcode_9b() // SBC A,E { A = subByte( E, F & Carry ); } void Z80::opcode_9c() // SBC A,H { A = subByte( H, F & Carry ); } void Z80::opcode_9d() // SBC A,L { A = subByte( L, F & Carry ); } void Z80::opcode_9e() // SBC A,(HL) { A = subByte( env_.readByte( HL() ), F & Carry ); } void Z80::opcode_9f() // SBC A,A { A = subByte( A, F & Carry ); } void Z80::opcode_a0() // AND B { A &= B; setFlagsPSZ(); } void Z80::opcode_a1() // AND C { A &= C; setFlagsPSZ(); } void Z80::opcode_a2() // AND D { A &= D; setFlagsPSZ(); } void Z80::opcode_a3() // AND E { A &= E; setFlagsPSZ(); } void Z80::opcode_a4() // AND H { A &= H; setFlagsPSZ(); } void Z80::opcode_a5() // AND L { A &= L; setFlagsPSZ(); } void Z80::opcode_a6() // AND (HL) { A &= env_.readByte( HL() ); setFlagsPSZ(); } void Z80::opcode_a7() // AND A { setFlagsPSZ(); } void Z80::opcode_a8() // XOR B { A ^= B; setFlags35PSZ000(); } void Z80::opcode_a9() // XOR C { A ^= C; setFlags35PSZ000(); } void Z80::opcode_aa() // XOR D { A ^= D; setFlags35PSZ000(); } void Z80::opcode_ab() // XOR E { A ^= E; setFlags35PSZ000(); } void Z80::opcode_ac() // XOR H { A ^= H; setFlags35PSZ000(); } void Z80::opcode_ad() // XOR L { A ^= L; setFlags35PSZ000(); } void Z80::opcode_ae() // XOR (HL) { A ^= env_.readByte( HL() ); setFlags35PSZ000(); } void Z80::opcode_af() // XOR A { A = 0; setFlags35PSZ000(); } void Z80::opcode_b0() // OR B { A |= B; setFlags35PSZ000(); } void Z80::opcode_b1() // OR C { A |= C; setFlags35PSZ000(); } void Z80::opcode_b2() // OR D { A |= D; setFlags35PSZ000(); } void Z80::opcode_b3() // OR E { A |= E; setFlags35PSZ000(); } void Z80::opcode_b4() // OR H { A |= H; setFlags35PSZ000(); } void Z80::opcode_b5() // OR L { A |= L; setFlags35PSZ000(); } void Z80::opcode_b6() // OR (HL) { A |= env_.readByte( HL() ); setFlags35PSZ000(); } void Z80::opcode_b7() // OR A { setFlags35PSZ000(); } void Z80::opcode_b8() // CP B { cmpByte( B ); } void Z80::opcode_b9() // CP C { cmpByte( C ); } void Z80::opcode_ba() // CP D { cmpByte( D ); } void Z80::opcode_bb() // CP E { cmpByte( E ); } void Z80::opcode_bc() // CP H { cmpByte( H ); } void Z80::opcode_bd() // CP L { cmpByte( L ); } void Z80::opcode_be() // CP (HL) { cmpByte( env_.readByte( HL() ) ); } void Z80::opcode_bf() // CP A { cmpByte( A ); } void Z80::opcode_c0() // RET NZ { if( ! (F & Zero) ) { retFromSub(); cycles_ += 2; } } void Z80::opcode_c1() // POP BC { C = env_.readByte( SP++ ); B = env_.readByte( SP++ ); } void Z80::opcode_c2() // JP NZ,nn { if( ! (F & Zero) ) PC = fetchWord(); else PC += 2; } void Z80::opcode_c3() // JP nn { PC = readWord( PC ); } void Z80::opcode_c4() // CALL NZ,nn { if( ! (F & Zero) ) { callSub( fetchWord() ); cycles_ += 2; } else { PC += 2; } } void Z80::opcode_c5() // PUSH BC { env_.writeByte( --SP, B ); env_.writeByte( --SP, C ); } void Z80::opcode_c6() // ADD A,n { addByte( fetchByte(), 0 ); } void Z80::opcode_c7() // RST 0 { callSub( 0x00 ); } void Z80::opcode_c8() // RET Z { if( F & Zero ) { retFromSub(); cycles_ += 2; } } void Z80::opcode_c9() // RET { retFromSub(); } void Z80::opcode_ca() // JP Z,nn { if( F & Zero ) PC = fetchWord(); else PC += 2; } void Z80::opcode_cb() // [Prefix] { unsigned op = fetchByte(); cycles_ += OpInfoCB_[ op ].cycles; (this->*(OpInfoCB_[ op ].handler))(); } void Z80::opcode_cc() // CALL Z,nn { if( F & Zero ) { callSub( fetchWord() ); cycles_ += 2; } else { PC += 2; } } void Z80::opcode_cd() // CALL nn { callSub( fetchWord() ); } void Z80::opcode_ce() // ADC A,n { addByte( fetchByte(), F & Carry ); } void Z80::opcode_cf() // RST 8 { callSub( 0x08 ); } void Z80::opcode_d0() // RET NC { if( ! (F & Carry) ) { retFromSub(); cycles_ += 2; } } void Z80::opcode_d1() // POP DE { E = env_.readByte( SP++ ); D = env_.readByte( SP++ ); } void Z80::opcode_d2() // JP NC,nn { if( ! (F & Carry) ) PC = fetchWord(); else PC += 2; } void Z80::opcode_d3() // OUT (n),A { env_.writePort( fetchByte(), A ); } void Z80::opcode_d4() // CALL NC,nn { if( ! (F & Carry) ) { callSub( fetchWord() ); cycles_ += 2; } else { PC += 2; } } void Z80::opcode_d5() // PUSH DE { env_.writeByte( --SP, D ); env_.writeByte( --SP, E ); } void Z80::opcode_d6() // SUB n { A = subByte( fetchByte(), 0 ); } void Z80::opcode_d7() // RST 10H { callSub( 0x10 ); } void Z80::opcode_d8() // RET C { if( F & Carry ) { retFromSub(); cycles_ += 2; } } void Z80::opcode_d9() // EXX { unsigned char x; x = B; B = B1; B1 = x; x = C; C = C1; C1 = x; x = D; D = D1; D1 = x; x = E; E = E1; E1 = x; x = H; H = H1; H1 = x; x = L; L = L1; L1 = x; } void Z80::opcode_da() // JP C,nn { if( F & Carry ) PC = fetchWord(); else PC += 2; } void Z80::opcode_db() // IN A,(n) { A = env_.readPort( fetchByte() ); } void Z80::opcode_dc() // CALL C,nn { if( F & Carry ) { callSub( fetchWord() ); cycles_ += 2; } else { PC += 2; } } void Z80::opcode_dd() // [IX Prefix] { do_opcode_xy( OpInfoDD_ ); IX &= 0xFFFF; } void Z80::opcode_de() // SBC A,n { A = subByte( fetchByte(), F & Carry ); } void Z80::opcode_df() // RST 18H { callSub( 0x18 ); } void Z80::opcode_e0() // RET PO { if( ! (F & Parity) ) { retFromSub(); cycles_ += 2; } } void Z80::opcode_e1() // POP HL { L = env_.readByte( SP++ ); H = env_.readByte( SP++ ); } void Z80::opcode_e2() // JP PO,nn { if( ! (F & Parity) ) PC = fetchWord(); else PC += 2; } void Z80::opcode_e3() // EX (SP),HL { unsigned char x; x = env_.readByte( SP ); env_.writeByte( SP, L ); L = x; x = env_.readByte( SP+1 ); env_.writeByte( SP+1, H ); H = x; } void Z80::opcode_e4() // CALL PO,nn { if( ! (F & Parity) ) { callSub( fetchWord() ); cycles_ += 2; } else { PC += 2; } } void Z80::opcode_e5() // PUSH HL { env_.writeByte( --SP, H ); env_.writeByte( --SP, L ); } void Z80::opcode_e6() // AND n { A &= fetchByte(); setFlagsPSZ(); } void Z80::opcode_e7() // RST 20H { callSub( 0x20 ); } void Z80::opcode_e8() // RET PE { if( F & Parity ) { retFromSub(); cycles_ += 2; } } void Z80::opcode_e9() // JP (HL) { PC = HL(); } void Z80::opcode_ea() // JP PE,nn { if( F & Parity ) PC = fetchWord(); else PC += 2; } void Z80::opcode_eb() // EX DE,HL { unsigned char x; x = D; D = H; H = x; x = E; E = L; L = x; } void Z80::opcode_ec() // CALL PE,nn { if( F & Parity ) { callSub( fetchWord() ); cycles_ += 2; } else { PC += 2; } } void Z80::opcode_ed() // [Prefix] { unsigned op = fetchByte(); if( OpInfoED_[ op ].handler ) { (this->*(OpInfoED_[ op ].handler))(); cycles_ += OpInfoED_[ op ].cycles; } else { cycles_ += OpInfo_[ 0 ].cycles; // NOP } } void Z80::opcode_ee() // XOR n { A ^= fetchByte(); setFlags35PSZ000(); } void Z80::opcode_ef() // RST 28H { callSub( 0x28 ); } void Z80::opcode_f0() // RET P { if( ! (F & Sign) ) { retFromSub(); cycles_ += 2; } } void Z80::opcode_f1() // POP AF { F = env_.readByte( SP++ ); A = env_.readByte( SP++ ); } void Z80::opcode_f2() // JP P,nn { if( ! (F & Sign) ) PC = fetchWord(); else PC += 2; } void Z80::opcode_f3() // DI { iflags_ &= ~(IFF1 | IFF2); } void Z80::opcode_f4() // CALL P,nn { if( ! (F & Sign) ) { callSub( fetchWord() ); cycles_ += 2; } else { PC += 2; } } void Z80::opcode_f5() // PUSH AF { env_.writeByte( --SP, A ); env_.writeByte( --SP, F ); } void Z80::opcode_f6() // OR n { A |= fetchByte(); setFlags35PSZ000(); } void Z80::opcode_f7() // RST 30H { callSub( 0x30 ); } void Z80::opcode_f8() // RET M { if( F & Sign ) { retFromSub(); cycles_ += 2; } } void Z80::opcode_f9() // LD SP,HL { SP = HL(); } void Z80::opcode_fa() // JP M,nn { if( F & Sign ) PC = fetchWord(); else PC += 2; } void Z80::opcode_fb() // EI { iflags_ |= IFF1 | IFF2; } void Z80::opcode_fc() // CALL M,nn { if( F & Sign ) { callSub( fetchWord() ); cycles_ += 2; } else { PC += 2; } } void Z80::opcode_fd() // [IY Prefix] { do_opcode_xy( OpInfoFD_ ); IY &= 0xFFFF; } void Z80::opcode_fe() // CP n { subByte( fetchByte(), 0 ); } void Z80::opcode_ff() // RST 38H { callSub( 0x38 ); } void Z80::do_opcode_xy( OpcodeInfo * info ) { unsigned op = fetchByte(); if( (op == 0xDD) || (op == 0xFD) ) { // Exit now, to avoid possible infinite loops PC--; cycles_ += OpInfo_[ 0 ].cycles; // NOP } else if( op == 0xED ) { // IX or IY prefix is ignored for this opcode opcode_ed(); } else { // Handle IX or IY prefix if possible if( info[ op ].handler ) { // Extended opcode is valid cycles_ += info[ op ].cycles; (this->*(info[ op ].handler))(); } else { // Extended opcode not valid, fall back to standard opcode cycles_ += OpInfo_[ op ].cycles; (this->*(OpInfo_[ op ].handler))(); } } }