package audio.gme;
// Nintendo Game Boy GB-Z80 CPU emulator
// http://www.slack.net/~ant/
/* Copyright (C) 2007 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module 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 Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
public class GbCpu extends ClassicEmu
{
public GbCpu() { rstBase = 0; }
// Resets registers, uses supplied physical memory, and
// maps all memory pages to unmapped
public final void reset( byte [] mem, int unmapped )
{
this.mem = mem;
a = 0;
bc = 0;
de = 0;
hl = 0;
pc = 0;
sp = 0xFFFF;
ph = 0x100;
cz = 1;
time = 0;
for ( int i = 0; i < pageCount + 1; i++ )
mapPage( i, unmapped );
}
static final int pageShift = 13;
static final int pageCount = 0x10000 >> pageShift;
static final int pageSize = 1 << pageShift;
// Maps address range to offset in physical memory
public final void mapMemory( int addr, int size, int offset )
{
assert addr % pageSize == 0;
assert size % pageSize == 0;
int firstPage = addr / pageSize;
for ( int i = size / pageSize; i-- > 0; )
mapPage( firstPage + i, offset + i * pageSize );
}
// Maps address to memory
public final int mapAddr( int addr ) { return pages [addr >> pageShift] + addr; }
// Emulation
// Registers. NOT kept updated during runCpu()
public int a, bc, de, hl, sp, pc;
// Base address for RST vectors (normally 0)
public int rstBase;
// Current time
public int time;
// Memory read and write handlers
protected int cpuRead ( int addr ) { return 0; }
protected void cpuWrite( int addr, int data ) { }
int pages [] = new int [pageCount + 1];
int cz, ph;
byte [] mem;
final void mapPage( int page, int offset )
{
if ( debug ) assert 0 <= page && page < pageCount + 1;
pages [page] = offset - page * pageSize;
}
// Runs until time >= 0
public final void runCpu()
{
// locals are faster, and first three are more efficient to access
final byte [] mem = this.mem;
int pc = this.pc;
int data = 0;
int time = this.time;
int a = this.a;
int bc = this.bc;
int de = this.de;
int hl = this.hl;
int sp = this.sp;
int cz = this.cz;
int ph = this.ph;
final int pages [] = this.pages;
final int instrTimes [] = this.instrTimes;
loop:
while ( time < 0 )
{
if ( debug )
{
assert 0 <= a && a < 0x00100;
assert 0 <= bc && bc < 0x10000;
assert 0 <= de && de < 0x10000;
assert 0 <= hl && hl < 0x10000;
assert 0 <= pc && pc < 0x10000;
assert 0 <= pc && pc < 0x10000;
}
int instr;
int opcode;
if ( (opcode = mem [instr = pages [pc >> pageShift] + pc] & 0xFF) == 0xCB )
{
// CB
// Source
this.time = (time += cbTimes [opcode = mem [instr + 1] & 0xFF]);
pc += 2;
int operand;
switch ( (operand = opcode & 7) )
{
case 0: data = bc >> 8; break;
case 1: data = bc & 0xFF; break;
case 2: data = de >> 8; break;
case 3: data = de & 0xFF; break;
case 4: data = hl >> 8; break;
case 5: data = hl & 0xFF; break;
case 6: data = cpuRead( hl ); break;
default: data = a; break;
}
// Operation
int operation;
switch ( (operation = opcode >> 3) )
{
case 0x08: // BIT 0,r
case 0x09: // BIT 1,r
case 0x0A: // BIT 2,r
case 0x0B: // BIT 3,r
case 0x0C: // BIT 4,r
case 0x0D: // BIT 5,r
case 0x0E: // BIT 6,r
case 0x0F: // BIT 7,r
cz = (cz & 0x100) | (data >> (operation - 0x08) & 1);
ph = (cz | 0x100) ^ 0x10; // N=0 H=1
continue;
case 0x00: // RLC r
cz = (data << 1 & 0x100) | data; // Z=* C=*
ph = data | 0x100; // N=0 H=0
data = (data << 1 & 0xFF) | (data >> 7);
break;
case 0x01: // RRC r
cz = (data << 8) | data; // Z=* C=*
ph = data | 0x100; // N=0 H=0
data = ((data & 1) << 7) | (data >> 1);
break;
case 0x04: // SLA r
cz = 0;
case 0x02: // RL r
cz = (data << 1) | (cz >> 8 & 1); // Z=* C=*
data = cz & 0xFF;
ph = cz | 0x100; // N=0 H=0
break;
case 0x05: // SRA r
cz = data << 1;
case 0x03: // RR r
data |= cz & 0x100;
case 0x07: // SRL r
cz = data << 8; // Z=* C=*
data >>= 1;
cz |= data;
ph = data | 0x100; // N=0 H=0
break;
case 0x06: // SWAP
data = (data >> 4) | (data << 4 & 0xFF);
cz = data;
ph = cz | 0x100;
break;
case 0x10: // RES 0,r
case 0x11: // RES 1,r
case 0x12: // RES 2,r
case 0x13: // RES 3,r
case 0x14: // RES 4,r
case 0x15: // RES 5,r
case 0x16: // RES 6,r
case 0x17: // RES 7,r
data &= ~(1 << (operation - 0x10));
break;
default:
/*
assert false;
case 0x18: // SET 0,r
case 0x19: // SET 1,r
case 0x1A: // SET 2,r
case 0x1B: // SET 3,r
case 0x1C: // SET 4,r
case 0x1D: // SET 5,r
case 0x1E: // SET 6,r
case 0x1F: // SET 7,r
*/
data |= 1 << (operation - 0x18);
break;
}
// Dest
switch ( operand )
{
case 0: bc = data << 8 | (bc & 0xFF); continue;
case 1: bc = (bc & 0xFF00) | data; continue;
case 2: de = data << 8 | (de & 0xFF); continue;
case 3: de = (de & 0xFF00) | data; continue;
case 4: hl = data << 8 | (hl & 0xFF); continue;
case 5: hl = (hl & 0xFF00) | data; continue;
case 6: cpuWrite( hl, data ); continue;
default: a = data; continue;
}
}
// Normal instruction
pc++;
this.time = (time += instrTimes [opcode]);
// Source
switch ( opcode )
{
case 0xF3: // DI
// TODO: implement
continue;
case 0xFB: // EI
// TODO: implement
continue;
case 0x76: // HALT
case 0x10: // STOP
case 0xD3: case 0xDB: case 0xDD: // Illegal
case 0xE3: case 0xE4: case 0xEB: case 0xEC: case 0xED:
case 0xF4: case 0xFC: case 0xFD:
pc--;
break loop;
case 0xE9: // LD PC,HL
pc = hl;
continue;
case 0xF9: // LD SP,HL
sp = hl;
continue;
case 0x37: // SCF
ph = cz | 0x100; // N=0 H=0
cz |= 0x100; // C=1 Z=-
continue;
case 0x3F: // CCF
ph = cz | 0x100; // N=0 H=0
cz ^= 0x100; // C=* Z=-
continue;
case 0x2F: // CPL
a ^= 0xFF;
ph = ~cz & 0xFF; // N=1 H=1
continue;
case 0x27:{// DAA
int h = ph ^ cz;
if ( (ph & 0x100) != 0 )
{
if ( (h & 0x10) != 0 || (a & 0x0F) > 9 )
a += 6;
if ( (cz & 0x100) != 0 || a > 0x9F )
a += 0x60;
}
else
{
if ( (h & 0x10) != 0 )
{
a -= 6;
if ( (cz & 0x100) == 0 )
a &= 0xFF;
}
if ( (cz & 0x100) != 0 )
a -= 0x60;
}
cz = (cz & 0x100) | a;
a &= 0xFF;
ph = (ph & 0x100) | a;
continue;
}
case 0xC0: // RET NZ
if ( ((byte) cz) != 0 )
break;
continue;
case 0xC8: // RET Z
if ( ((byte) cz) == 0 )
break;
continue;
case 0xD0: // RET NC
if ( (cz & 0x100) == 0 )
break;
continue;
case 0xD8: // RET C
if ( (cz & 0x100) != 0 )
break;
continue;
case 0xF5: // PUSH AF
data = (cz >> 4 & 0x10) | (a << 8);
data |= ~ph >> 2 & 0x40;
data |= (ph ^ cz) << 1 & 0x20;
if ( ((byte) cz) == 0 )
data |= 0x80;
break;
case 0x22: // LD (HL+),A
case 0x2A: // LD A,(HL+)
data = hl;
hl = (hl + 1) & 0xFFFF;
break;
case 0x32: // LD (HL-),A
case 0x3A: // LD A,(HL-)
data = hl;
hl = (hl - 1) & 0xFFFF;
break;
case 0x7E: // LD A,(HL)
case 0x23: // INC HL
case 0x29: // ADD HL,HL
case 0x2B: // DEC HL
case 0xE5: // PUSH HL
data = hl;
break;
case 0x02: // LD (BC),A
case 0x0A: // LD A,(BC)
case 0x03: // INC BC
case 0x09: // ADD HL,BC
case 0x0B: // DEC BC
case 0xC5: // PUSH BC
data = bc;
break;
case 0x12: // LD (DE),A
case 0x1A: // LD A,(DE)
case 0x13: // INC DE
case 0x19: // ADD HL,DE
case 0x1B: // DEC DE
case 0xD5: // PUSH DE
data = de;
break;
case 0x33: // INC SP
case 0x39: // ADD HL,SP
case 0x3B: // DEC SP
data = sp;
break;
case 0xF0: // LDH A,(n)
case 0xE0: // LDH (n),A
case 0x06: // LD B,n
case 0x0E: // LD C,n
case 0x16: // LD D,n
case 0x1E: // LD E,n
case 0x26: // LD H,n
case 0x2E: // LD L,n
case 0x36: // LD (HL),n
case 0x3E: // LD A,n
case 0xC6: // ADD n
case 0xCE: // ADC n
case 0xD6: // SUB n
case 0xDE: // SBC n
case 0xE6: // AND n
case 0xEE: // XOR n
case 0xF6: // OR n
case 0xFE: // CP n
case 0x18: // JR r
case 0x20: // JR NZ,r
case 0x28: // JR Z,r
case 0x30: // JR NC,r
case 0x38: // JR C,r
case 0xF8: // LD HL,SPs
case 0xE8: // ADD SP,s
data = mem [instr + 1] & 0xFF;
pc++;
break;
case 0x01: // LD BC,nn
case 0x11: // LD DE,nn
case 0x21: // LD HL,nn
case 0x31: // LD SP,nn
case 0xC2: // JP NZ,nn
case 0xC3: // JP nn
case 0xC4: // CALL NZ,nn
case 0xCA: // JP Z,nn
case 0xCC: // CALL Z,nn
case 0xCD: // CALL nn
case 0xD2: // JP NC,nn
case 0xD4: // CALL NC,nn
case 0xDA: // JP C,nn
case 0xDC: // CALL C,nn
case 0xEA: // LD (nn),A
case 0x08: // LD (nn),SP
case 0xFA: // LD A,(nn)
data = (mem [instr + 2] & 0xFF) << 8 | (mem [instr + 1] & 0xFF);
pc += 2;
break;
case 0x34: // INC (HL)
case 0x35: // DEC (HL)
case 0x46: // LD B,(HL)
case 0x4E: // LD C,(HL)
case 0x56: // LD D,(HL)
case 0x5E: // LD E,(HL)
case 0x66: // LD H,(HL)
case 0x6E: // LD L,(HL)
case 0x86: // ADD (HL)
case 0x8E: // ADC (HL)
case 0x96: // SUB (HL)
case 0x9E: // SBC (HL)
case 0xA6: // AND (HL)
case 0xAE: // XOR (HL)
case 0xB6: // OR (HL)
case 0xBE: // CP (HL)
data = cpuRead( hl );
break;
case 0x3C: // INC A
case 0x3D: // DEC A
case 0x47: // LD B,A
case 0x4F: // LD C,A
case 0x57: // LD D,A
case 0x5F: // LD E,A
case 0x67: // LD H,A
case 0x6F: // LD L,A
case 0x77: // LD (HL),A
case 0x87: // ADD A
case 0x8F: // ADC A
case 0x97: // SUB A
case 0x9F: // SBC A
case 0xA7: // AND A
case 0xAF: // XOR A
case 0xB7: // OR A
case 0xBF: // CP A
data = a;
break;
case 0x04: // INC B
case 0x05: // DEC B
case 0x48: // LD C,B
case 0x50: // LD D,B
case 0x58: // LD E,B
case 0x60: // LD H,B
case 0x68: // LD L,B
case 0x70: // LD (HL),B
case 0x78: // LD A,B
case 0x80: // ADD B
case 0x88: // ADC B
case 0x90: // SUB B
case 0x98: // SBC B
case 0xA0: // AND B
case 0xA8: // XOR B
case 0xB0: // OR B
case 0xB8: // CP B
data = bc >> 8;
break;
case 0xF2: // LDH A,(C)
case 0xE2: // LDH (C),A
case 0x0C: // INC C
case 0x0D: // DEC C
case 0x41: // LD B,C
case 0x51: // LD D,C
case 0x59: // LD E,C
case 0x61: // LD H,C
case 0x69: // LD L,C
case 0x71: // LD (HL),C
case 0x79: // LD A,C
case 0x81: // ADD C
case 0x89: // ADC C
case 0x91: // SUB C
case 0x99: // SBC C
case 0xA1: // AND C
case 0xA9: // XOR C
case 0xB1: // OR C
case 0xB9: // CP C
data = bc & 0xFF;
break;
case 0x14: // INC D
case 0x15: // DEC D
case 0x42: // LD B,D
case 0x4A: // LD C,D
case 0x5A: // LD E,D
case 0x62: // LD H,D
case 0x6A: // LD L,D
case 0x72: // LD (HL),D
case 0x7A: // LD A,D
case 0x82: // ADD D
case 0x8A: // ADC D
case 0x92: // SUB D
case 0x9A: // SBC D
case 0xA2: // AND D
case 0xAA: // XOR D
case 0xB2: // OR D
case 0xBA: // CP D
data = de >> 8;
break;
case 0x1C: // INC E
case 0x1D: // DEC E
case 0x43: // LD B,E
case 0x4B: // LD C,E
case 0x53: // LD D,E
case 0x63: // LD H,E
case 0x6B: // LD L,E
case 0x73: // LD (HL),E
case 0x7B: // LD A,E
case 0x83: // ADD E
case 0x8B: // ADC E
case 0x93: // SUB E
case 0x9B: // SBC E
case 0xA3: // AND E
case 0xAB: // XOR E
case 0xB3: // OR E
case 0xBB: // CP E
data = de & 0xFF;
break;
case 0x24: // INC H
case 0x25: // DEC H
case 0x44: // LD B,H
case 0x4C: // LD C,H
case 0x54: // LD D,H
case 0x5C: // LD E,H
case 0x6C: // LD L,H
case 0x74: // LD (HL),H
case 0x7C: // LD A,H
case 0x84: // ADD H
case 0x8C: // ADC H
case 0x94: // SUB H
case 0x9C: // SBC H
case 0xA4: // AND H
case 0xAC: // XOR H
case 0xB4: // OR H
case 0xBC: // CP H
data = hl >> 8;
break;
case 0x2C: // INC L
case 0x2D: // DEC L
case 0x45: // LD B,L
case 0x4D: // LD C,L
case 0x55: // LD D,L
case 0x5D: // LD E,L
case 0x65: // LD H,L
case 0x75: // LD (HL),L
case 0x7D: // LD A,L
case 0x85: // ADD L
case 0x8D: // ADC L
case 0x95: // SUB L
case 0x9D: // SBC L
case 0xA5: // AND L
case 0xAD: // XOR L
case 0xB5: // OR L
case 0xBD: // CP L
data = hl & 0xFF;
break;
}
// Operation
switch ( opcode )
{
case 0x09: // ADD HL,BC
case 0x19: // ADD HL,DE
case 0x29: // ADD HL,HL
case 0x39: // ADD HL,SP
ph = hl ^ data;
data += hl;
hl = data & 0xFFFF;
ph ^= data;
cz = (cz & 0xFF) | (data >> 8 & 0x100); // C=* Z=-
ph = ((ph >> 8) ^ cz) | 0x100; // N=0 H=*
continue;
case 0x88: // ADC B
case 0x89: // ADC C
case 0x8A: // ADC D
case 0x8B: // ADC E
case 0x8C: // ADC H
case 0x8D: // ADC L
case 0x8E: // ADC (HL)
case 0x8F: // ADC A
case 0xCE: // ADC n
ph = 0x100 | (a ^ data); // N=0 H=*
cz = a + data + (cz >> 8 & 1); // C=* Z=*
a = cz & 0xFF;
continue;
case 0x80: // ADD B
case 0x81: // ADD C
case 0x82: // ADD D
case 0x83: // ADD E
case 0x84: // ADD H
case 0x85: // ADD L
case 0x86: // ADD (HL)
case 0x87: // ADD A
case 0xC6: // ADD n
ph = 0x100 | (a ^ data); // N=0 H=*
cz = a + data; // C=* Z=*
a = cz & 0xFF;
continue;
case 0xB8: // CP B
case 0xB9: // CP C
case 0xBA: // CP D
case 0xBB: // CP E
case 0xBC: // CP H
case 0xBD: // CP L
case 0xBE: // CP (HL)
case 0xBF: // CP A
case 0xFE: // CP n
ph = a ^ data; // N=1 H=*
cz = a - data; // C=* Z=*
continue;
case 0x90: // SUB B
case 0x91: // SUB C
case 0x92: // SUB D
case 0x93: // SUB E
case 0x94: // SUB H
case 0x95: // SUB L
case 0x96: // SUB (HL)
case 0x97: // SUB A
case 0xD6: // SUB n
ph = a ^ data; // N=1 H=*
cz = a - data; // C=* Z=*
a = cz & 0xFF;
continue;
case 0x98: // SBC B
case 0x99: // SBC C
case 0x9A: // SBC D
case 0x9B: // SBC E
case 0x9C: // SBC H
case 0x9D: // SBC L
case 0x9E: // SBC (HL)
case 0x9F: // SBC A
case 0xDE: // SBC n
ph = a ^ data; // N=1 H=*
cz = a - data - (cz >> 8 & 1); // C=* Z=*
a = cz & 0xFF;
continue;
case 0xA0: // AND B
case 0xA1: // AND C
case 0xA2: // AND D
case 0xA3: // AND E
case 0xA4: // AND H
case 0xA5: // AND L
case 0xA6: // AND (HL)
case 0xA7: // AND A
case 0xE6: // AND n
a &= data;
cz = a; // C=0 Z=*
ph = ~a; // N=0 H=1
continue;
case 0xB0: // OR B
case 0xB1: // OR C
case 0xB2: // OR D
case 0xB3: // OR E
case 0xB4: // OR H
case 0xB5: // OR L
case 0xB6: // OR (HL)
case 0xB7: // OR A
case 0xF6: // OR n
a |= data;
cz = a; // C=0 Z=*
ph = a | 0x100; // N=0 H=0
continue;
case 0xA8: // XOR B
case 0xA9: // XOR C
case 0xAA: // XOR D
case 0xAB: // XOR E
case 0xAC: // XOR H
case 0xAD: // XOR L
case 0xAE: // XOR (HL)
case 0xAF: // XOR A
case 0xEE: // XOR n
a ^= data;
cz = a; // C=0 Z=*
ph = a | 0x100; // N=0 H=0
continue;
case 0x17: // RLA
cz = (a << 1) | (cz >> 8 & 1);
ph = cz | 0x100;
a = cz & 0xFF;
cz |= 1;
continue;
case 0x07: // RLCA
cz = a << 1;
a = (cz & 0xFF) | (a >> 7);
ph = a | 0x100;
cz |= 1;
continue;
case 0x1F: // RRA
a |= cz & 0x100;
cz = a << 8 | 1; // Z=0 C=*
a >>= 1;
ph = 0x100; // N=0 H=0
continue;
case 0x0F: // RRCA
cz = a << 8 | 1; // Z=0 C=*
a = ((a & 1) << 7) | (a >> 1);
ph = 0x100; // N=0 H=0
continue;
case 0xE8: // ADD SP,s
case 0xF8:{// LD HL,SPs
int t = (sp + (byte) data) & 0xFFFF;
cz = (((sp & 0xFF) + data) & 0x100) | 1; // Z=0 C=*
ph = (sp ^ data ^ t) | 0x100; // N=0 H=*
data = t;
break;
}
case 0x0B: // DEC BC
case 0x1B: // DEC DE
case 0x2B: // DEC HL
case 0x3B: // DEC SP
data = (data - 1) & 0xFFFF;
break;
case 0x05: // DEC B
case 0x0D: // DEC C
case 0x15: // DEC D
case 0x1D: // DEC E
case 0x25: // DEC H
case 0x2D: // DEC L
case 0x35: // DEC (HL)
case 0x3D: // DEC A
ph = data; // N=1 H=*
data = (data - 1) & 0xFF;
cz = (cz & 0x100) | data; // C=- Z=*
break;
case 0x03: // INC BC
case 0x13: // INC DE
case 0x23: // INC HL
case 0x33: // INC SP
data = (data + 1) & 0xFFFF;
break;
case 0x04: // INC B
case 0x0C: // INC C
case 0x14: // INC D
case 0x1C: // INC E
case 0x24: // INC H
case 0x2C: // INC L
case 0x34: // INC (HL)
case 0x3C: // INC A
ph = data | 0x100; // N=0 H=*
data = (data + 1) & 0xFF;
cz = (cz & 0x100) | data; // C=- Z=*
break;
case 0xD9: // RETI
// TODO: EI
case 0xC0: // RET NZ
case 0xC8: // RET Z
case 0xD0: // RET NC
case 0xD8: // RET C
time += 12;
case 0xC9:{// RET
data = pages [sp >> pageShift] + sp;
pc = (mem [data + 1] & 0xFF) << 8 | (mem [data] & 0xFF);
sp = (sp + 2) & 0xFFFF;
continue;
}
case 0xC1: // POP BC
case 0xD1: // POP DE
case 0xE1: // POP HL
case 0xF1:{// POP AF
data = pages [sp >> pageShift] + sp;
data = (mem [data + 1] & 0xFF) << 8 | (mem [data] & 0xFF);
sp = (sp + 2) & 0xFFFF;
break;
}
case 0xC4: // CALL NZ,nn
case 0x20: // JR NZ,r
case 0xC2: // JP NZ,nn
if ( ((byte) cz) != 0 )
break;
continue;
case 0xCC: // CALL Z,nn
case 0x28: // JR Z,r
case 0xCA: // JP Z,nn
if ( ((byte) cz) == 0 )
break;
continue;
case 0xD4: // CALL NC,nn
case 0x30: // JR NC,r
case 0xD2: // JP NC,nn
if ( (cz & 0x100) == 0 )
break;
continue;
case 0xDC: // CALL C,nn
case 0x38: // JR C,r
case 0xDA: // JP C,nn
if ( (cz & 0x100) != 0 )
break;
continue;
case 0xFF: // RST $38
case 0xC7: // RST $00
case 0xCF: // RST $08
case 0xD7: // RST $10
case 0xDF: // RST $18
case 0xE7: // RST $20
case 0xEF: // RST $28
case 0xF7: // RST $30
data = (opcode & 0x38) + rstBase;
break;
}
// Destination
switch ( opcode )
{
case 0xC2: // JP NZ,nn
case 0xCA: // JP Z,nn
case 0xD2: // JP NC,nn
case 0xDA: // JP C,nn
time += 4;
case 0xC3: // JP nn
pc = data;
continue;
case 0x20: // JR NZ,r
case 0x28: // JR Z,r
case 0x30: // JR NC,r
case 0x38: // JR C,r
time += 4;
case 0x18: // JR r
pc = (pc + (byte) data) & 0xFFFF;
continue;
case 0xC4: // CALL NZ,nn
case 0xCC: // CALL Z,nn
case 0xD4: // CALL NC,nn
case 0xDC: // CALL C,nn
time += 12;
case 0xC7: // RST $00
case 0xCF: // RST $08
case 0xD7: // RST $10
case 0xDF: // RST $18
case 0xE7: // RST $20
case 0xEF: // RST $28
case 0xF7: // RST $30
case 0xFF: // RST $38
case 0xCD:{// CALL nn
int t = pc;
pc = data;
data = t;
}
case 0xC5: // PUSH BC
case 0xD5: // PUSH DE
case 0xE5: // PUSH HL
case 0xF5:{// PUSH AF
sp = (sp - 2) & 0xFFFF;
int offset = pages [sp >> pageShift] + sp;
mem [offset + 1] = (byte) (data >> 8);
mem [offset ] = (byte) data;
continue;
}
case 0xF1:{// POP AF
cz = (data << 4 & 0x100) | ((data >> 7 & 1) ^ 1);
ph = (~data << 2 & 0x100) | (data >> 1 & 0x10);
a = data >> 8;
continue;
}
case 0xF0: // LDH A,(n)
case 0xF2: // LDH A,(C)
data += 0xFF00;
case 0xFA: // LD A,(nn)
case 0x0A: // LD A,(BC)
case 0x1A: // LD A,(DE)
case 0x7E: // LD A,(HL)
case 0x2A: // LD A,(HL+)
case 0x3A: // LD A,(HL-)
a = cpuRead( data );
continue;
case 0xE0: // LDH (n),A
case 0xE2: // LDH (C),A
data += 0xFF00;
case 0xEA: // LD (nn),A
case 0x02: // LD (BC),A
case 0x12: // LD (DE),A
case 0x22: // LD (HL+),A
case 0x32: // LD (HL-),A
cpuWrite( data, a );
continue;
case 0x08: // LD (nn),SP
cpuWrite( data, sp & 0xFF );
cpuWrite( (data + 1) & 0xFFFF, sp >> 8 );
continue;
case 0x34: // INC (HL)
case 0x35: // DEC (HL)
case 0x36: // LD (HL),n
case 0x70: // LD (HL),B
case 0x71: // LD (HL),C
case 0x72: // LD (HL),D
case 0x73: // LD (HL),E
case 0x74: // LD (HL),H
case 0x75: // LD (HL),L
case 0x77: // LD (HL),A
cpuWrite( hl, data );
continue;
case 0x01: // LD BC,nn
case 0x03: // INC BC
case 0x0B: // DEC BC
case 0xC1: // POP BC
bc = data;
continue;
case 0x11: // LD DE,nn
case 0x13: // INC DE
case 0x1B: // DEC DE
case 0xD1: // POP DE
de = data;
continue;
case 0xF8: // LD HL,SPs
case 0x21: // LD HL,nn
case 0x23: // INC HL
case 0x2B: // DEC HL
case 0xE1: // POP HL
hl = data;
continue;
case 0xE8: // ADD SP,s
case 0x31: // LD SP,nn
case 0x33: // INC SP
case 0x3B: // DEC SP
sp = data;
continue;
case 0x3C: // INC A
case 0x3D: // DEC A
case 0x3E: // LD A,n
case 0x78: // LD A,B
case 0x79: // LD A,C
case 0x7A: // LD A,D
case 0x7B: // LD A,E
case 0x7C: // LD A,H
case 0x7D: // LD A,L
a = data;
continue;
case 0x04: // INC B
case 0x05: // DEC B
case 0x06: // LD B,n
case 0x41: // LD B,C
case 0x42: // LD B,D
case 0x43: // LD B,E
case 0x44: // LD B,H
case 0x45: // LD B,L
case 0x46: // LD B,(HL)
case 0x47: // LD B,A
bc = (data << 8) | (bc & 0xFF);
continue;
case 0x14: // INC D
case 0x15: // DEC D
case 0x16: // LD D,n
case 0x50: // LD D,B
case 0x51: // LD D,C
case 0x53: // LD D,E
case 0x54: // LD D,H
case 0x55: // LD D,L
case 0x56: // LD D,(HL)
case 0x57: // LD D,A
de = (data << 8) | (de & 0xFF);
continue;
case 0x24: // INC H
case 0x25: // DEC H
case 0x26: // LD H,n
case 0x60: // LD H,B
case 0x61: // LD H,C
case 0x62: // LD H,D
case 0x63: // LD H,E
case 0x65: // LD H,L
case 0x66: // LD H,(HL)
case 0x67: // LD H,A
hl = (data << 8) | (hl & 0xFF);
continue;
case 0x0C: // INC C
case 0x0D: // DEC C
case 0x0E: // LD C,n
case 0x48: // LD C,B
case 0x4A: // LD C,D
case 0x4B: // LD C,E
case 0x4C: // LD C,H
case 0x4D: // LD C,L
case 0x4E: // LD C,(HL)
case 0x4F: // LD C,A
bc = (bc & 0xFF00) | data;
continue;
case 0x1C: // INC E
case 0x1D: // DEC E
case 0x1E: // LD E,n
case 0x58: // LD E,B
case 0x59: // LD E,C
case 0x5A: // LD E,D
case 0x5C: // LD E,H
case 0x5D: // LD E,L
case 0x5E: // LD E,(HL)
case 0x5F: // LD E,A
de = (de & 0xFF00) | data;
continue;
case 0x2C: // INC L
case 0x2D: // DEC L
case 0x2E: // LD L,n
case 0x68: // LD L,B
case 0x69: // LD L,C
case 0x6A: // LD L,D
case 0x6B: // LD L,E
case 0x6C: // LD L,H
case 0x6E: // LD L,(HL)
case 0x6F: // LD L,A
hl = (hl & 0xFF00) | data;
continue;
}
}
this.a = a;
this.bc = bc;
this.de = de;
this.hl = hl;
this.sp = sp;
this.pc = pc;
this.ph = ph;
this.cz = cz;
this.time = time;
}
static final int [] instrTimes = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
4,12, 8, 8, 4, 4, 8, 4,20, 8, 8, 8, 4, 4, 8, 4,// 0
4,12, 8, 8, 4, 4, 8, 4,12, 8, 8, 8, 4, 4, 8, 4,// 1
8,12, 8, 8, 4, 4, 8, 4, 8, 8, 8, 8, 4, 4, 8, 4,// 2
8,12, 8, 8,12,12,12, 4, 8, 8, 8, 8, 4, 4, 8, 4,// 3
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// 4
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// 5
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// 6
8, 8, 8, 8, 8, 8, 0, 8, 4, 4, 4, 4, 4, 4, 8, 4,// 7
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// 8
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// 9
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// A
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,// B
8,12,12,16,12,16, 8,16, 8,16,12, 0,12,24, 8,16,// C
8,12,12, 0,12,16, 8,16, 8, 4,12, 0,12, 0, 8,16,// D
12,12, 8, 0, 0,16, 8,16,16, 4,16, 0, 0, 0, 8,16,// E
12,12, 8, 4, 0,16, 8,16,12, 8,16, 4, 0, 0, 8,16,// F
};
static final int [] cbTimes = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// 0
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// 1
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// 2
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// 3
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,// 4
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,// 5
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,// 6
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,// 7
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// 8
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// 9
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// A
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// B
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// C
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// D
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// E
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,// F
};
}