package audio.gme;
// Nintendo SNES SPC-700 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 SpcCpu extends MusicEmu
{
// Registers. NOT kept updated during runCpu()
public int a, x, y, psw, sp, pc;
// Current time
public int time;
// Memory read and write handlers
protected int cpuRead ( int addr ) { return 0; }
protected void cpuWrite( int addr, int data ) { }
// Resets registers and uses supplied physical memory
public final void reset( byte [] mem )
{
this.mem = mem;
a = 0;
x = 0;
y = 0;
sp = 0xFF;
pc = 0;
psw = 0x04;
time = 0;
}
public final void setPsw( int psw ) { this.psw = psw; }
private byte [] mem;
static final int [] instrTimes =
{// 0 1 2 3 4 5 6 7 8 9 A B C D E F
2,8,4,5,3,4,3,6,2,6,5,4,5,4,6,8, // 0
2,8,4,5,4,5,5,6,5,5,6,5,2,2,4,6, // 1
2,8,4,5,3,4,3,6,2,6,5,4,5,4,5,2, // 2
2,8,4,5,4,5,5,6,5,5,6,5,2,2,3,8, // 3
2,8,4,5,3,4,3,6,2,6,4,4,5,4,6,6, // 4
2,8,4,5,4,5,5,6,5,5,4,5,2,2,4,3, // 5
2,8,4,5,3,4,3,6,2,6,4,4,5,4,5,5, // 6
2,8,4,5,4,5,5,6,5,5,5,5,2,2,3,6, // 7
2,8,4,5,3,4,3,6,2,6,5,4,5,2,4,5, // 8
2,8,4,5,4,5,5,6,5,5,5,5,2,2,12,5,// 9
3,8,4,5,3,4,3,6,2,6,4,4,5,2,4,4, // A
2,8,4,5,4,5,5,6,5,5,5,5,2,2,3,4, // B
3,8,4,5,4,5,4,7,2,5,6,4,5,2,4,9, // C
2,8,4,5,5,6,6,7,4,5,5,5,2,2,6,3, // D
2,8,4,5,3,4,3,6,2,4,5,3,4,3,4,0, // E
2,8,4,5,4,5,5,6,3,4,5,4,2,2,4,0, // F
};
// Hex value in name to clarify code and bit shifting.
// Flag stored in indicated variable during emulation
static final int n80 = 0x80; // (nz & 0x880) != 0
static final int v40 = 0x40; // psw
static final int p20 = 0x20; // psw, dp == 0x100
static final int b10 = 0x10; // psw
static final int h08 = 0x08; // psw
static final int i04 = 0x04; // psw
static final int z02 = 0x02; // (byte) nz == 0
static final int c01 = 0x01; // (c & 0x100) != 0
// 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 nz;
int pc = this.pc;
int a = this.a;
int x = this.x;
int y = this.y;
int psw = this.psw;
int sp = (this.sp + 1) | 0x100;
int time = this.time;
final int [] instrTimes = this.instrTimes;
// unpack psw
int c, dp;
c = psw << 8;
dp = psw << 3 & 0x100;
nz = (psw << 4 & 0x800) | (~psw & z02);
int data = 0;
int addr = 0;
loop:
while ( time < 0 )
{
if ( debug )
{
assert 0 <= a && a < 0x100;
assert 0 <= x && x < 0x100;
assert 0 <= y && y < 0x100;
assert 0 <= pc && pc < 0x10000;
assert 0x100 <= sp && sp < 0x200;
assert dp == 0 || dp == 0x100;
}
int opcode;
this.time = (time += instrTimes [opcode = mem [pc] & 0xFF]);
switch ( opcode )
{
//////// Often used
case 0xE4: // MOV A, d
a = nz = cpuRead( mem [pc + 1] & 0xFF | dp );
pc += 2;
continue;
case 0xF5: // MOV A, !a+X
a = nz = cpuRead( ((mem [pc + 2] & 0xFF) << 8 | (mem [pc + 1] & 0xFF)) + x );
pc += 3;
continue;
case 0xF4: // MOV A, d+X
a = nz = cpuRead( (mem [pc + 1] + x) & 0xFF | dp );
pc += 2;
continue;
case 0xEB: // MOV Y, d
y = nz = cpuRead( mem [pc + 1] & 0xFF | dp );
pc += 2;
continue;
case 0x2F: // BRA r
pc += mem [pc + 1] + 2;
continue;
case 0x90: // BCC r
pc += 2;
if ( (c & 0x100) == 0 )
{
pc += mem [pc - 1];
time += 2;
}
continue;
case 0xB0: // BCS r
pc += 2;
if ( (c & 0x100) != 0 )
{
pc += mem [pc - 1];
time += 2;
}
continue;
case 0xF0: // BEQ r
pc += 2;
if ( ((byte) nz) == 0 )
{
pc += mem [pc - 1];
time += 2;
}
continue;
case 0xD0: // BNE r
pc += 2;
if ( ((byte) nz) != 0 )
{
pc += mem [pc - 1];
time += 2;
}
continue;
case 0x30: // BMI r
pc += 2;
if ( (nz & 0x880) != 0 )
{
pc += mem [pc - 1];
time += 2;
}
continue;
case 0x10: // BPL r
pc += 2;
if ( (nz & 0x880) == 0 )
{
pc += mem [pc - 1];
time += 2;
}
continue;
case 0x50: // BVC r
pc += 2;
if ( (psw & v40) == 0 )
{
pc += mem [pc - 1];
time += 2;
}
continue;
case 0x70: // BVS r
pc += 2;
if ( (psw & v40) != 0 )
{
pc += mem [pc - 1];
time += 2;
}
continue;
//////// Self-contained
case 0xFE: // DBNZ Y, r
pc += 2;
if ( (y = (y - 1) & 0xFF) != 0 )
break;
continue;
case 0xEF: // SLEEP
case 0xFF: // STOP
break loop;
case 0x9C: // DEC A
pc++;
a = (nz = a - 1) & 0xFF;
continue;
case 0xBC: // INC A
pc++;
a = (nz = a + 1) & 0xFF;
continue;
case 0x1D: // DEC X
pc++;
x = (nz = x - 1) & 0xFF;
continue;
case 0x3D: // INC X
pc++;
x = (nz = x + 1) & 0xFF;
continue;
case 0xDC: // DEC Y
pc++;
y = (nz = y - 1) & 0xFF;
continue;
case 0xFC: // INC Y
pc++;
y = (nz = y + 1) & 0xFF;
continue;
case 0x1C: // ASL A
c = 0;
case 0x3C:{// ROL A
int t = c >> 8 & 1;
c = a << 1;
a = (nz = c | t) & 0xFF;
pc++;
continue;
}
case 0x5C: // LSR A
c = 0;
case 0x7C: // ROR A
nz = ((c & 0x100) | a) >> 1;
c = a << 8;
a = nz;
pc++;
continue;
case 0x9F: // XCN A
pc++;
a = nz = a >> 4 | ((a & 0x0F) << 4);
continue;
case 0xDF: // DAA A
pc++;
if ( a > 0x99 || (c & 0x100) != 0 )
{
a += 0x60;
c = 0x100;
}
if ( (a & 0x0F) > 9 || (psw & h08) != 0 )
a += 0x06;
nz = (a &= 0xFF);
continue;
case 0xBE: // DAS A
pc++;
if ( a > 0x99 || (c & 0x100) == 0 )
{
a -= 0x60;
c = 0;
}
if ( (a & 0x0F) > 9 || (psw & h08) == 0 )
a -= 0x06;
nz = (a &= 0xFF);
continue;
case 0x9E:{// DIV YA, X
pc++;
int ya = y << 8 | a;
psw &= ~(h08 | v40);
if ( y >= x )
psw |= v40;
if ( (y & 15) >= (x & 15) )
psw |= h08;
if ( y < (x << 1) )
{
a = ya / x;
y = ya - a * x;
}
else
{
a = 255 - (ya - (x << 9)) / (256 - x);
y = x + (ya - (x << 9)) % (256 - x);
}
nz = (a &= 0xFF);
continue;
}
case 0xCF:{// MUL YA
pc++;
int t = y * a;
a = t & 0xFF;
nz = (t >> 1 | t) & 0x7F;
nz |= (y = t >> 8);
continue;
}
case 0x00: // NOP
pc++;
continue;
case 0x60: // CLRC
pc++;
c = 0;
continue;
case 0x80: // SETC
pc++;
c = ~0;
continue;
case 0xED: // NOTC
pc++;
c ^= 0x100;
continue;
case 0x20: // CLRP
pc++;
dp = 0;
continue;
case 0x40: // SETP
pc++;
dp = 0x100;
continue;
case 0xE0: // CLRV
pc++;
psw &= ~(v40 | h08);
continue;
case 0xC0: // DI
pc++;
psw |= i04;
continue;
case 0xA0: // EI
pc++;
psw &= ~i04;
continue;
case 0x5D: // MOV X, A
pc++;
x = nz = a;
continue;
case 0xFD: // MOV Y, A
pc++;
y = nz = a;
continue;
case 0x7D: // MOV A, X
pc++;
a = nz = x;
continue;
case 0xDD: // MOV A, Y
pc++;
a = nz = y;
continue;
case 0x9D: // MOV X, SP
pc++;
x = nz = (sp - 1) & 0xFF;
continue;
case 0xBD: // MOV SP, X
pc++;
sp = (x + 1) | 0x100;
continue;
case 0xBF: // MOV A, (X)+
pc++;
a = nz = cpuRead( x + dp );
x = (x + 1) & 0xFF;
continue;
case 0xD9: // MOV d+Y, X
cpuWrite( (mem [pc + 1] + y) & 0xFF | dp, x );
pc += 2;
continue;
case 0xD6: // MOV !a+Y, A
cpuWrite( ((mem [pc + 2] & 0xFF) << 8 | (mem [pc + 1] & 0xFF)) + y, a );
pc += 3;
continue;
case 0xD5: // MOV !a+X, A
cpuWrite( ((mem [pc + 2] & 0xFF) << 8 | (mem [pc + 1] & 0xFF)) + x, a );
pc += 3;
continue;
case 0xF9: // MOV X, d+Y
x = nz = cpuRead( (mem [pc + 1] + y) & 0xFF | dp );
pc += 2;
continue;
case 0xD7:{// MOV [d]+Y, A
int t = mem [pc + 1];
cpuWrite( ((mem [(t + 1) & 0xFF | dp] & 0xFF) << 8 | (mem [t & 0xFF | dp] & 0xFF)) + y, a );
pc += 2;
continue;
}
case 0xC7:{// MOV [d+X], A
int t = mem [pc + 1] + x;
cpuWrite( (mem [(t + 1) & 0xFF | dp] & 0xFF) << 8 | (mem [t & 0xFF | dp] & 0xFF), a );
pc += 2;
continue;
}
case 0xC6: // MOV (X), A
pc++;
cpuWrite( x + dp, a );
continue;
case 0xAF: // MOV (X)+, A
pc++;
cpuWrite( x + dp, a );
x = (x + 1) & 0xFF;
continue;
case 0x8F: // MOV d, #i
cpuWrite( mem [pc + 2] & 0xFF | dp, mem [pc + 1] );
pc += 3;
continue;
case 0xFA: // MOV dd, ds
cpuWrite( mem [pc + 2] & 0xFF | dp, cpuRead( mem [pc + 1] & 0xFF | dp ) );
pc += 3;
continue;
case 0xCA: // MOV1 m.b, C
data = mem [pc + 2];
addr = (data & 0x1F) << 8 | (mem [pc + 1] & 0xFF);
data = data >> 5 & 7;
cpuWrite( addr, cpuRead( addr ) & ~(1 << data) | ((c & 0x100) >> (8 - data)) );
pc += 3;
continue;
case 0xEA: // NOT1 m.b
data = mem [pc + 2];
addr = (data & 0x1F) << 8 | (mem [pc + 1] & 0xFF);
cpuWrite( addr, cpuRead( addr ) ^ (1 << (data >> 5 & 7)) );
pc += 3;
continue;
case 0x4A: // AND1 C, m.b
case 0xAA: // MOV1 C, m.b
case 0x0A: // OR1 C, m.b
case 0x6A: // AND1 C, /m.b
case 0x2A: // OR1 C, /m.b
case 0x8A: // EOR1 C, m.b
data = mem [pc + 2];
data = cpuRead( (data & 0x1F) << 8 | (mem [pc + 1] & 0xFF) ) << (8 - (data >> 5 & 7));
pc += 3;
switch ( opcode )
{
case 0x4A: // AND1 C, m.b
c &= data;
continue;
case 0xAA: // MOV1 C, m.b
c = data;
continue;
case 0x0A: // OR1 C, m.b
c |= data;
continue;
case 0x6A: // AND1 C, /m.b
c &= ~data;
continue;
case 0x2A: // OR1 C, /m.b
c |= ~data;
continue;
default:
//case 0x8A: // EOR1 C, m.b
c ^= data;
continue;
}
case 0x02: // SET1 d.0
case 0x22: // SET1 d.1
case 0x42: // SET1 d.2
case 0x62: // SET1 d.3
case 0x82: // SET1 d.4
case 0xA2: // SET1 d.5
case 0xC2: // SET1 d.6
case 0xE2: // SET1 d.7
case 0x12: // CLR1 d.0
case 0x32: // CLR1 d.1
case 0x52: // CLR1 d.2
case 0x72: // CLR1 d.3
case 0x92: // CLR1 d.4
case 0xB2: // CLR1 d.5
case 0xD2: // CLR1 d.6
case 0xF2:{// CLR1 d.7
data = cpuRead( addr = mem [pc + 1] & 0xFF | dp );
int t = 1 << (opcode >> 5);
data |= t;
if ( (opcode & 0x10) != 0 )
data ^= t;
cpuWrite( addr, data );
pc += 2;
continue;
}
case 0x2D: // PUSH A
pc++;
mem [sp = (sp - 1) | 0x100] = (byte) a;
continue;
case 0x4D: // PUSH X
pc++;
mem [sp = (sp - 1) | 0x100] = (byte) x;
continue;
case 0x6D: // PUSH Y
pc++;
mem [sp = (sp - 1) | 0x100] = (byte) y;
continue;
case 0x0D: // PUSH PSW
case 0x0F:{// BRK
// calculate PSW
int t = psw & ~(n80 | p20 | z02 | c01);
t |= c >> 8 & c01;
t |= dp >> 3 & p20;
t |= ((nz >> 4) | nz) & n80;
if ( ((byte) nz) == 0 ) t |= z02;
pc++;
if ( opcode == 0x0F ) // BRK
{
mem [(sp - 1) | 0x100] = (byte) (pc >> 8);
mem [sp = (sp - 2) | 0x100] = (byte) pc;
pc = (mem [0xFFDF] & 0xFF) << 8 | (mem [0xFFDE] & 0xFF);
psw = (psw | b10) & ~i04;
}
mem [sp = (sp - 1) | 0x100] = (byte) t;
continue;
}
case 0xAE: // POP A
pc++;
a = mem [sp] & 0xFF;
sp = (sp + 1) | 0x100;
continue;
case 0xCE: // POP X
pc++;
x = mem [sp] & 0xFF;
sp = (sp + 1) | 0x100;
continue;
case 0xEE: // POP Y
pc++;
y = mem [sp] & 0xFF;
sp = (sp + 1) | 0x100;
continue;
case 0x8E: // POP PSW
case 0x7F: // RET1
pc++;
psw = mem [sp];
sp = (sp - 0xFF) | 0x100;
if ( opcode == 0x7F ) // RET1
{
pc = (mem [(sp - 0xFF) | 0x100] & 0xFF) << 8 | (mem [sp] & 0xFF);
sp = (sp - 0xFE) | 0x100;
}
// unpack psw
c = psw << 8;
dp = psw << 3 & 0x100;
nz = (psw << 4 & 0x800) | (~psw & z02);
continue;
case 0x6F: // RET
pc = (mem [(sp - 0xFF) | 0x100] & 0xFF) << 8 | (mem [sp] & 0xFF);
sp = (sp - 0xFE) | 0x100;
continue;
case 0xDA:{// MOVW d, YA
int t = mem [pc + 1];
cpuWrite( t & 0xFF | dp, a );
cpuWrite( (t + 1) & 0xFF | dp, y );
pc += 2;
continue;
}
case 0x1A: // DECW d
case 0x3A: // INCW d
case 0x5A: // CMPW YA, d
case 0x7A: // ADDW YA, d
case 0x9A: // SUBW YA, d
case 0xBA:{// MOVW YA, d
addr = mem [pc + 1] & 0xFF | dp;
data = (mem [addr + 1] & 0xFF) << 8 | (mem [addr] & 0xFF);
// addr >= 0xEF || addr <= 0xFF
if ( (addr ^ 0xFF) <= 0x11 ) // 1%
data = cpuRead( addr + 1 ) << 8 | cpuRead( addr );
pc += 2;
switch ( opcode )
{
case 0x1A: // DECW d
data -= 2;
case 0x3A: // INCW d
data++;
nz = (data & 0x7F) | (data >> 1 & 0x7F) | (data >> 8);
mem [addr ] = (byte) data;
mem [addr + 1] = (byte) (data >> 8);
// addr >= 0xEF || addr <= 0xFF
if ( (addr ^ 0xFF) <= 0x11 ) // 1%
{
cpuWrite( addr, data );
cpuWrite( addr + 1, data >> 8 );
}
continue;
case 0xBA: // MOVW YA, d
nz = 0x7F & (a = data & 0xFF);
nz |= (a >> 1) | (y = data >> 8);
continue;
case 0x5A: // CMPW YA, d
data = (y << 8 | a) - data;
nz = (data & 0x7F) | (data >> 1 & 0x7F);
nz = (byte) (nz | (data >>= 8));
c = ~data;
continue;
case 0x9A: // SUBW YA, d
data = -data & 0xFFFF;
default: {
//case 0x7A: // ADDW YA, d
int t = (data >> 8) ^ y;
a = 0xFF & (data += y << 8 | a);
t ^= (c = data >> 8);
nz = (a & 0x7F) | (a >> 1) | (y = c & 0xFF);
psw = (psw & ~(v40 | h08)) |
(t >> 1 & h08) |
((t + 0x80) >> 2 & v40);
continue;
}
}
}
//////// Misc
case 0x13: // BBC d.0, r
case 0x33: // BBC d.1, r
case 0x53: // BBC d.2, r
case 0x73: // BBC d.3, r
case 0x93: // BBC d.4, r
case 0xB3: // BBC d.5, r
case 0xD3: // BBC d.6, r
case 0xF3: // BBC d.7, r
case 0x03: // BBS d.0, r
case 0x23: // BBS d.1, r
case 0x43: // BBS d.2, r
case 0x63: // BBS d.3, r
case 0x83: // BBS d.4, r
case 0xA3: // BBS d.5, r
case 0xC3: // BBS d.6, r
case 0xE3: // BBS d.7, r
case 0x6E: // DBNZ d, r
case 0x2E: // CBNE d, r
data = cpuRead( (addr = mem [pc + 1] & 0xFF | dp) );
pc += 3;
break;
case 0xDE: // CBNE d+X, r
data = cpuRead( (addr = (mem [pc + 1] + x) & 0xFF | dp) );
pc += 3;
break;
case 0x1F: // JMP [!a+X]
case 0x3F: // CALL !a
case 0x5F: // JMP !a
case 0xC5: // MOV !a, A
case 0xC9: // MOV !a, X
case 0xCC: // MOV !a, Y
addr = (mem [pc + 2] & 0xFF) << 8 | (mem [pc + 1] & 0xFF);
pc += 3;
break;
case 0x4F: // PCALL u
addr = 0xFF00 | (mem [pc + 1] & 0xFF);
pc += 2;
break;
//////// nz = operand, data = operand 2, addr = address of operand 2
case 0x38: // AND d, #i
case 0x58: // EOR d, #i
case 0x78: // CMP d, #i
case 0x98: // ADC d, #i
case 0xB8: // SBC d, #i
case 0x18: // OR d, #i
nz = mem [pc + 1] & 0xFF;
data = cpuRead( addr = mem [pc + 2] & 0xFF | dp );
pc += 3;
break;
case 0x39: // AND (X), (Y)
case 0x59: // EOR (X), (Y)
case 0x79: // CMP (X), (Y)
case 0x99: // ADC (X), (Y)
case 0xB9: // SBC (X), (Y)
case 0x19: // OR (X), (Y)
nz = cpuRead( y + dp );
data = cpuRead( addr = x + dp );
pc++;
break;
case 0x29: // AND dd, ds
case 0x49: // EOR dd, ds
case 0x69: // CMP dd, ds
case 0x89: // ADC dd, ds
case 0xA9: // SBC dd, ds
case 0x09: // OR dd, ds
nz = cpuRead( mem [pc + 1] & 0xFF | dp );
data = cpuRead( addr = mem [pc + 2] & 0xFF | dp );
pc += 3;
break;
//////// nz = operand
case 0x25: // AND A, !a
case 0x45: // EOR A, !a
case 0x65: // CMP A, !a
case 0x85: // ADC A, !a
case 0xA5: // SBC A, !a
case 0x05: // OR A, !a
case 0xE5: // MOV A, !a
case 0x0E: // TSET1 !a
case 0x4E: // TCLR1 !a
case 0x0C: // ASL !a
case 0x2C: // ROL !a
case 0x4C: // LSR !a
case 0x6C: // ROR !a
case 0x8C: // DEC !a
case 0xAC: // INC !a
case 0x1E: // CMP X, !a
case 0xE9: // MOV X, !a
case 0x5E: // CMP Y, !a
case 0xEC: // MOV Y, !a
nz = cpuRead( addr = (mem [pc + 2] & 0xFF) << 8 | (mem [pc + 1] & 0xFF) );
pc += 3;
break;
case 0x35: // AND A, !a+X
case 0x55: // EOR A, !a+X
case 0x75: // CMP A, !a+X
case 0x95: // ADC A, !a+X
case 0xB5: // SBC A, !a+X
case 0x15: // OR A, !a+X
nz = cpuRead( ((mem [pc + 2] & 0xFF) << 8 | (mem [pc + 1] & 0xFF)) + x );
pc += 3;
break;
case 0x36: // AND A, !a+Y
case 0x56: // EOR A, !a+Y
case 0x76: // CMP A, !a+Y
case 0x96: // ADC A, !a+Y
case 0xB6: // SBC A, !a+Y
case 0x16: // OR A, !a+Y
case 0xF6: // MOV A, !a+Y
nz = cpuRead( ((mem [pc + 2] & 0xFF) << 8 | (mem [pc + 1] & 0xFF)) + y );
pc += 3;
break;
case 0x26: // AND A, (X)
case 0x46: // EOR A, (X)
case 0x66: // CMP A, (X)
case 0x86: // ADC A, (X)
case 0xA6: // SBC A, (X)
case 0x06: // OR A, (X)
case 0xE6: // MOV A, (X)
nz = cpuRead( x + dp );
pc++;
break;
case 0x24: // AND A, d
case 0x44: // EOR A, d
case 0x64: // CMP A, d
case 0x84: // ADC A, d
case 0xA4: // SBC A, d
case 0x04: // OR A, d
case 0x0B: // ASL d
case 0x2B: // ROL d
case 0x4B: // LSR d
case 0x6B: // ROR d
case 0x8B: // DEC d
case 0xAB: // INC d
case 0x3E: // CMP X, d
case 0xF8: // MOV X, d
case 0x7E: // CMP Y, d
nz = cpuRead( addr = mem [pc + 1] & 0xFF | dp );
pc += 2;
break;
case 0x34: // AND A, d+X
case 0x54: // EOR A, d+X
case 0x74: // CMP A, d+X
case 0x94: // ADC A, d+X
case 0xB4: // SBC A, d+X
case 0x14: // OR A, d+X
case 0x1B: // ASL d+X
case 0x3B: // ROL d+X
case 0x5B: // LSR d+X
case 0x7B: // ROR d+X
case 0x9B: // DEC d+X
case 0xBB: // INC d+X
case 0xFB: // MOV Y, d+X
nz = cpuRead( addr = (mem [pc + 1] + x) & 0xFF | dp );
pc += 2;
break;
case 0x37: // AND A, [d]+Y
case 0x57: // EOR A, [d]+Y
case 0x77: // CMP A, [d]+Y
case 0x97: // ADC A, [d]+Y
case 0xB7: // SBC A, [d]+Y
case 0x17: // OR A, [d]+Y
case 0xF7:{// MOV A, [d]+Y
int t = mem [pc + 1];
nz = cpuRead( ((mem [(t + 1) & 0xFF | dp] & 0xFF) << 8 | (mem [t & 0xFF | dp] & 0xFF)) + y );
pc += 2;
break;
}
case 0x27: // AND A, [d+X]
case 0x47: // EOR A, [d+X]
case 0x67: // CMP A, [d+X]
case 0x87: // ADC A, [d+X]
case 0xA7: // SBC A, [d+X]
case 0x07: // OR A, [d+X]
case 0xE7:{// MOV A, [d+X]
int t = mem [pc + 1] + x;
nz = cpuRead( (mem [(t + 1) & 0xFF | dp] & 0xFF) << 8 | (mem [t & 0xFF | dp] & 0xFF) );
pc += 2;
break;
}
case 0x28: // AND A, #i
case 0x48: // EOR A, #i
case 0x68: // CMP A, #i
case 0x88: // ADC A, #i
case 0xA8: // SBC A, #i
case 0x08: // OR A, #i
case 0xE8: // MOV A, #i
case 0xC8: // CMP X, #i
case 0xCD: // MOV X, #i
case 0x8D: // MOV Y, #i
case 0xAD: // CMP Y, #i
nz = mem [pc + 1] & 0xFF;
pc += 2;
break;
case 0xC4: // MOV d, A
case 0xD8: // MOV d, X
case 0xCB: // MOV d, Y
addr = mem [pc + 1] & 0xFF | dp;
pc += 2;
break;
case 0xD4: // MOV d+X, A
case 0xDB: // MOV d+X, Y
addr = (mem [pc + 1] + x) & 0xFF | dp;
pc += 2;
break;
}
// Operation
switch ( opcode )
{
case 0x5F: // JMP !a
pc = addr;
continue;
case 0x1F: // JMP [!a+X]
addr += x;
pc = (mem [addr + 1] & 0xFF) << 8 | (mem [addr] & 0xFF);
continue;
case 0x13: // BBC d.0, r
case 0x33: // BBC d.1, r
case 0x53: // BBC d.2, r
case 0x73: // BBC d.3, r
case 0x93: // BBC d.4, r
case 0xB3: // BBC d.5, r
case 0xD3: // BBC d.6, r
case 0xF3: // BBC d.7, r
case 0x03: // BBS d.0, r
case 0x23: // BBS d.1, r
case 0x43: // BBS d.2, r
case 0x63: // BBS d.3, r
case 0x83: // BBS d.4, r
case 0xA3: // BBS d.5, r
case 0xC3: // BBS d.6, r
case 0xE3: // BBS d.7, r
if ( (((data >> (opcode >> 5)) ^ (opcode >> 4)) & 1) != 0 )
{
pc += mem [pc - 1];
time += 2;
}
continue;
case 0x6E: // DBNZ d, r
cpuWrite( addr, --data );
if ( data != 0 )
{
pc += mem [pc - 1];
time += 2;
}
continue;
case 0xDE: // CBNE d+X, r
case 0x2E: // CBNE d, r
if ( data == a )
continue;
case 0xFE: // DBNZ Y, r
time += 2;
pc += mem [pc - 1];
continue;
case 0x01: // TCALL 0
case 0x11: // TCALL 1
case 0x21: // TCALL 2
case 0x31: // TCALL 3
case 0x41: // TCALL 4
case 0x51: // TCALL 5
case 0x61: // TCALL 6
case 0x71: // TCALL 7
case 0x81: // TCALL 8
case 0x91: // TCALL 9
case 0xA1: // TCALL 10
case 0xB1: // TCALL 11
case 0xC1: // TCALL 12
case 0xD1: // TCALL 13
case 0xE1: // TCALL 14
case 0xF1: // TCALL 15
addr = 0xFFDE - (opcode >> 3);
addr = (mem [addr + 1] & 0xFF) << 8 | (mem [addr] & 0xFF);
case 0x4F: // PCALL u
case 0x3F: // CALL !a
mem [(sp - 1) | 0x100] = (byte) (pc >> 8);
mem [sp = (sp - 2) | 0x100] = (byte) pc;
pc = addr;
continue;
case 0x65: // CMP A, !a
case 0x75: // CMP A, !a+X
case 0x76: // CMP A, !a+Y
case 0x68: // CMP A, #i
case 0x66: // CMP A, (X)
case 0x67: // CMP A, [d+X]
case 0x77: // CMP A, [d]+Y
case 0x64: // CMP A, d
case 0x74: // CMP A, d+X
c = ~(nz = a - nz);
nz = (byte) nz;
continue;
case 0x1E: // CMP X, !a
case 0xC8: // CMP X, #i
case 0x3E: // CMP X, d
c = ~(nz = x - nz);
nz = (byte) nz;
continue;
case 0x5E: // CMP Y, !a
case 0xAD: // CMP Y, #i
case 0x7E: // CMP Y, d
c = ~(nz = y - nz);
nz = (byte) nz;
continue;
case 0x78: // CMP d, #i
case 0x69: // CMP dd, ds
case 0x79: // CMP (X), (Y)
c = ~(nz = data - nz);
nz = (byte) nz;
continue;
case 0xA5: // SBC A, !a
case 0xB5: // SBC A, !a+X
case 0xB6: // SBC A, !a+Y
case 0xA8: // SBC A, #i
case 0xA6: // SBC A, (X)
case 0xA7: // SBC A, [d+X]
case 0xB7: // SBC A, [d]+Y
case 0xA4: // SBC A, d
case 0xB4: // SBC A, d+X
nz ^= 0xFF;
case 0x85: // ADC A, !a
case 0x95: // ADC A, !a+X
case 0x96: // ADC A, !a+Y
case 0x88: // ADC A, #i
case 0x86: // ADC A, (X)
case 0x87: // ADC A, [d+X]
case 0x97: // ADC A, [d]+Y
case 0x84: // ADC A, d
case 0x94:{// ADC A, d+X
int flags = a ^ nz;
flags ^= (c = nz += a + (c >> 8 & 1));
psw = (psw & ~(v40 | h08)) |
(flags >> 1 & h08) |
((flags + 0x80) >> 2 & v40);
a = nz & 0xFF;
continue;
}
case 0xB9: // SBC (X), (Y)
case 0xB8: // SBC d, #i
case 0xA9: // SBC dd, ds
nz ^= 0xFF;
case 0x99: // ADC (X), (Y)
case 0x98: // ADC d, #i
case 0x89:{// ADC dd, ds
int flags = nz ^ data;
flags ^= (c = nz += data + (c >> 8 & 1));
psw = (psw & ~(v40 | h08)) |
(flags >> 1 & h08) |
((flags + 0x80) >> 2 & v40);
cpuWrite( addr, nz );
continue;
}
case 0x25: // AND A, !a
case 0x35: // AND A, !a+X
case 0x36: // AND A, !a+Y
case 0x28: // AND A, #i
case 0x26: // AND A, (X)
case 0x27: // AND A, [d+X]
case 0x37: // AND A, [d]+Y
case 0x24: // AND A, d
case 0x34: // AND A, d+X
nz = a &= nz;
continue;
case 0x39: // AND (X), (Y)
case 0x38: // AND d, #i
case 0x29: // AND dd, ds
cpuWrite( addr, nz &= data );
continue;
case 0x05: // OR A, !a
case 0x15: // OR A, !a+X
case 0x16: // OR A, !a+Y
case 0x08: // OR A, #i
case 0x06: // OR A, (X)
case 0x07: // OR A, [d+X]
case 0x17: // OR A, [d]+Y
case 0x04: // OR A, d
case 0x14: // OR A, d+X
nz = a |= nz;
continue;
case 0x19: // OR (X), (Y)
case 0x18: // OR d, #i
case 0x09: // OR dd, ds
cpuWrite( addr, nz |= data );
continue;
case 0x45: // EOR A, !a
case 0x55: // EOR A, !a+X
case 0x56: // EOR A, !a+Y
case 0x48: // EOR A, #i
case 0x46: // EOR A, (X)
case 0x47: // EOR A, [d+X]
case 0x57: // EOR A, [d]+Y
case 0x44: // EOR A, d
case 0x54: // EOR A, d+X
nz = a ^= nz;
continue;
case 0x59: // EOR (X), (Y)
case 0x58: // EOR d, #i
case 0x49: // EOR dd, ds
cpuWrite( addr, nz ^= data );
continue;
case 0x8C: // DEC !a
case 0x8B: // DEC d
case 0x9B: // DEC d+X
cpuWrite( addr, --nz );
continue;
case 0xAC: // INC !a
case 0xAB: // INC d
case 0xBB: // INC d+X
cpuWrite( addr, ++nz );
continue;
case 0x0C: // ASL !a
case 0x0B: // ASL d
case 0x1B: // ASL d+X
c = 0;
case 0x2C: // ROL !a
case 0x2B: // ROL d
case 0x3B:{// ROL d+X
int t = c >> 8 & 1;
c = nz << 1;
cpuWrite( addr, nz = c | t );
continue;
}
case 0x4C: // LSR !a
case 0x4B: // LSR d
case 0x5B: // LSR d+X
c = 0;
case 0x6C: // ROR !a
case 0x6B: // ROR d
case 0x7B:{// ROR d+X
int t = c & 0x100;
c = nz << 8;
cpuWrite( addr, nz = (nz | t) >> 1 );
continue;
}
case 0x4E:{// TCLR1 !a
int t = nz & ~a;
nz = (byte) (a - nz);
cpuWrite( addr, t );
continue;
}
case 0x0E:{// TSET1 !a
int t = nz | a;
nz = (byte) (a - nz);
cpuWrite( addr, t );
continue;
}
case 0xC4: // MOV d, A
case 0xD4: // MOV d+X, A
case 0xC5: // MOV !a, A
cpuWrite( addr, a );
continue;
case 0xD8: // MOV d, X
case 0xC9: // MOV !a, X
cpuWrite( addr, x );
continue;
case 0xCB: // MOV d, Y
case 0xDB: // MOV d+X, Y
case 0xCC: // MOV !a, Y
cpuWrite( addr, y );
continue;
case 0xE5: // MOV A, !a
case 0xF6: // MOV A, !a+Y
case 0xE8: // MOV A, #i
case 0xE6: // MOV A, (X)
case 0xBF: // MOV A, (X)+
case 0x7D: // MOV A, X
case 0xDD: // MOV A, Y
case 0xE7: // MOV A, [d+X]
case 0xF7: // MOV A, [d]+Y
a = nz;
continue;
case 0xE9: // MOV X, !a
case 0xCD: // MOV X, #i
case 0x5D: // MOV X, A
case 0x9D: // MOV X, SP
case 0xF8: // MOV X, d
x = nz;
continue;
case 0xEC: // MOV Y, !a
case 0x8D: // MOV Y, #i
case 0xFD: // MOV Y, A
case 0xFB: // MOV Y, d+X
y = nz;
continue;
}
}
// calculate PSW
psw &= ~(n80 | p20 | z02 | c01);
psw |= c >> 8 & c01;
psw |= dp >> 3 & p20;
psw |= ((nz >> 4) | nz) & n80;
if ( ((byte) nz) == 0 ) psw |= z02;
this.pc = pc;
this.a = a;
this.x = x;
this.y = y;
this.psw = psw;
this.sp = (sp - 1) & 0xFF;
this.time = time;
}
}