forked from KolibriOS/kolibrios
ea1a60faa3
git-svn-id: svn://kolibrios.org@9837 a494cfbc-eb01-0410-851d-a64ba20cac60
1312 lines
26 KiB
C++
1312 lines
26 KiB
C++
/********************************************************************************/
|
|
/* */
|
|
/* CZ80 opcode include source file */
|
|
/* C Z80 emulator version 0.91 */
|
|
/* Copyright 2004-2005 Stephane Dallongeville */
|
|
/* */
|
|
/********************************************************************************/
|
|
|
|
#if CZ80_USE_JUMPTABLE
|
|
goto *JumpTable[Opcode];
|
|
#else
|
|
switch (Opcode)
|
|
{
|
|
#endif
|
|
|
|
// 8 BITS LOAD
|
|
|
|
OP(0x00): // NOP
|
|
|
|
OP(0x40): // LD B,B
|
|
OP(0x49): // LD C,C
|
|
OP(0x52): // LD D,D
|
|
OP(0x5b): // LD E,E
|
|
OP(0x64): // LD H,H
|
|
OP(0x6d): // LD L,L
|
|
OP(0x7f): // LD A,A
|
|
OP_NOP:
|
|
RET(4)
|
|
|
|
OP(0x41): // LD B,C
|
|
OP(0x42): // LD B,D
|
|
OP(0x43): // LD B,E
|
|
OP(0x44): // LD B,H
|
|
OP(0x45): // LD B,L
|
|
OP(0x47): // LD B,A
|
|
|
|
OP(0x48): // LD C,B
|
|
OP(0x4a): // LD C,D
|
|
OP(0x4b): // LD C,E
|
|
OP(0x4c): // LD C,H
|
|
OP(0x4d): // LD C,L
|
|
OP(0x4f): // LD C,A
|
|
|
|
OP(0x50): // LD D,B
|
|
OP(0x51): // LD D,C
|
|
OP(0x53): // LD D,E
|
|
OP(0x54): // LD D,H
|
|
OP(0x55): // LD D,L
|
|
OP(0x57): // LD D,A
|
|
|
|
OP(0x58): // LD E,B
|
|
OP(0x59): // LD E,C
|
|
OP(0x5a): // LD E,D
|
|
OP(0x5c): // LD E,H
|
|
OP(0x5d): // LD E,L
|
|
OP(0x5f): // LD E,A
|
|
|
|
OP(0x60): // LD H,B
|
|
OP(0x61): // LD H,C
|
|
OP(0x62): // LD H,D
|
|
OP(0x63): // LD H,E
|
|
OP(0x65): // LD H,L
|
|
OP(0x67): // LD H,A
|
|
|
|
OP(0x68): // LD L,B
|
|
OP(0x69): // LD L,C
|
|
OP(0x6a): // LD L,D
|
|
OP(0x6b): // LD L,E
|
|
OP(0x6c): // LD L,H
|
|
OP(0x6f): // LD L,A
|
|
|
|
OP(0x78): // LD A,B
|
|
OP(0x79): // LD A,C
|
|
OP(0x7a): // LD A,D
|
|
OP(0x7b): // LD A,E
|
|
OP(0x7c): // LD A,H
|
|
OP(0x7d): // LD A,L
|
|
OP_LD_R_R:
|
|
zR8((Opcode >> 3) & 7) = zR8(Opcode & 7);
|
|
RET(4)
|
|
|
|
OP(0x06): // LD B,#imm
|
|
OP(0x0e): // LD C,#imm
|
|
OP(0x16): // LD D,#imm
|
|
OP(0x1e): // LD E,#imm
|
|
OP(0x26): // LD H,#imm
|
|
OP(0x2e): // LD L,#imm
|
|
OP(0x3e): // LD A,#imm
|
|
OP_LD_R_imm:
|
|
zR8(Opcode >> 3) = FETCH_BYTE;
|
|
RET(7)
|
|
|
|
OP(0x46): // LD B,(HL)
|
|
OP(0x4e): // LD C,(HL)
|
|
OP(0x56): // LD D,(HL)
|
|
OP(0x5e): // LD E,(HL)
|
|
OP(0x66): // LD H,(HL)
|
|
OP(0x6e): // LD L,(HL)
|
|
OP(0x7e): // LD A,(HL)
|
|
/* OP_LD_R_mHL: */
|
|
PRE_IO
|
|
READ_BYTE(zHL, zR8((Opcode >> 3) & 7))
|
|
POST_IO
|
|
RET(7)
|
|
|
|
OP(0x70): // LD (HL),B
|
|
OP(0x71): // LD (HL),C
|
|
OP(0x72): // LD (HL),D
|
|
OP(0x73): // LD (HL),E
|
|
OP(0x74): // LD (HL),H
|
|
OP(0x75): // LD (HL),L
|
|
OP(0x77): // LD (HL),A
|
|
/* OP_LD_mHL_R: */
|
|
PRE_IO
|
|
WRITE_BYTE(zHL, zR8(Opcode & 7))
|
|
POST_IO
|
|
RET(7)
|
|
|
|
OP(0x36): // LD (HL), #imm
|
|
/* OP_LD_mHL_imm: */
|
|
PRE_IO
|
|
WRITE_BYTE(zHL, FETCH_BYTE)
|
|
POST_IO
|
|
RET(10)
|
|
|
|
{
|
|
uint16_t adr;
|
|
|
|
OP(0x0a): // LD A,(BC)
|
|
OP_LOAD_A_mBC:
|
|
adr = zBC;
|
|
goto OP_LOAD_A_mxx;
|
|
|
|
OP(0x1a): // LD A,(DE)
|
|
OP_LOAD_A_mDE:
|
|
adr = zDE;
|
|
|
|
OP_LOAD_A_mxx:
|
|
PRE_IO
|
|
READ_BYTE(adr, zA)
|
|
POST_IO
|
|
RET(7)
|
|
|
|
OP(0x3a): // LD A,(nn)
|
|
OP_LOAD_A_mNN:
|
|
PRE_IO
|
|
FETCH_WORD(adr)
|
|
READ_BYTE(adr, zA)
|
|
POST_IO
|
|
RET(13)
|
|
|
|
OP(0x02): // LD (BC),A
|
|
OP_LOAD_mBC_A:
|
|
adr = zBC;
|
|
goto OP_LOAD_mxx_A;
|
|
|
|
OP(0x12): // LD (DE),A
|
|
OP_LOAD_mDE_A:
|
|
adr = zDE;
|
|
|
|
OP_LOAD_mxx_A:
|
|
PRE_IO
|
|
WRITE_BYTE(adr, zA)
|
|
POST_IO
|
|
RET(7)
|
|
|
|
OP(0x32): // LD (nn),A
|
|
OP_LOAD_mNN_A:
|
|
PRE_IO
|
|
FETCH_WORD(adr)
|
|
WRITE_BYTE(adr, zA)
|
|
POST_IO
|
|
RET(13)
|
|
}
|
|
|
|
// 16 BITS LOAD
|
|
|
|
OP(0x01): // LD BC,nn
|
|
OP(0x11): // LD DE,nn
|
|
OP(0x21): // LD HL,nn
|
|
OP_LOAD_RR_imm16:
|
|
FETCH_WORD(zR16(Opcode >> 4))
|
|
RET(10)
|
|
|
|
OP(0x31): // LD SP,nn
|
|
OP_LOAD_SP_imm16:
|
|
FETCH_WORD(zSP)
|
|
RET(10)
|
|
|
|
OP(0xf9): // LD SP,HL
|
|
OP_LD_SP_xx:
|
|
zSP = data->W;
|
|
RET(6)
|
|
|
|
{
|
|
uint16_t adr;
|
|
|
|
OP(0x2a): // LD HL,(nn)
|
|
OP_LD_xx_mNN:
|
|
PRE_IO
|
|
FETCH_WORD(adr)
|
|
READ_WORD_LE(adr, data->W)
|
|
POST_IO
|
|
RET(16)
|
|
|
|
OP(0x22): // LD (nn),HL
|
|
OP_LD_mNN_xx:
|
|
PRE_IO
|
|
FETCH_WORD(adr)
|
|
WRITE_WORD_LE(adr, data->W)
|
|
POST_IO
|
|
RET(16)
|
|
}
|
|
|
|
// PUSH / POP
|
|
|
|
OP(0xf1): // POP AF
|
|
OP_POP_AF:
|
|
{
|
|
uint16_t res;
|
|
|
|
PRE_IO
|
|
POP_16(res)
|
|
zA = res >> 8;
|
|
zF = res & 0xFF;
|
|
POST_IO
|
|
RET(10)
|
|
}
|
|
|
|
OP(0xc1): // POP BC
|
|
OP(0xd1): // POP DE
|
|
OP_POP_RR:
|
|
data = pzR16((Opcode >> 4) & 3);
|
|
|
|
OP(0xe1): // POP HL
|
|
OP_POP:
|
|
PRE_IO
|
|
POP_16(data->W)
|
|
POST_IO
|
|
RET(10)
|
|
|
|
OP(0xf5): // PUSH AF
|
|
OP_PUSH_AF:
|
|
PRE_IO
|
|
PUSH_16((zA << 8) | zF);
|
|
POST_IO
|
|
RET(11)
|
|
|
|
OP(0xc5): // PUSH BC
|
|
OP(0xd5): // PUSH DE
|
|
OP_PUSH_RR:
|
|
data = pzR16((Opcode >> 4) & 3);
|
|
|
|
OP(0xe5): // PUSH HL
|
|
OP_PUSH:
|
|
PRE_IO
|
|
PUSH_16(data->W);
|
|
POST_IO
|
|
RET(11)
|
|
|
|
// EXCHANGE & BLOCK TRANSFERT / SEARCH
|
|
|
|
{
|
|
uint16_t tmp;
|
|
|
|
OP(0x08): // EX AF,AF'
|
|
OP_EX_AF_AF2:
|
|
tmp = zFA;
|
|
zFA = zFA2;
|
|
zFA2 = tmp;
|
|
RET(4)
|
|
|
|
OP(0xeb): // EX DE,HL
|
|
OP_EX_DE_HL:
|
|
tmp = zDE;
|
|
zDE = zHL;
|
|
zHL = tmp;
|
|
RET(4)
|
|
|
|
OP(0xd9): // EXX
|
|
OP_EXX:
|
|
tmp = zBC;
|
|
zBC = zBC2;
|
|
zBC2 = tmp;
|
|
tmp = zDE;
|
|
zDE = zDE2;
|
|
zDE2 = tmp;
|
|
tmp = zHL;
|
|
zHL = zHL2;
|
|
zHL2 = tmp;
|
|
RET(4)
|
|
}
|
|
|
|
OP(0xe3): // EX HL,(SP)
|
|
{
|
|
uint16_t adr;
|
|
uint16_t tmp;
|
|
|
|
OP_EX_xx_mSP:
|
|
PRE_IO
|
|
adr = zSP;
|
|
tmp = data->W;
|
|
READ_WORD_LE(adr, data->W)
|
|
WRITE_WORD_LE(adr, tmp)
|
|
POST_IO
|
|
RET(19)
|
|
}
|
|
|
|
// 8 BITS ARITHMETIC
|
|
|
|
OP(0x04): // INC B
|
|
OP(0x0c): // INC C
|
|
OP(0x14): // INC D
|
|
OP(0x1c): // INC E
|
|
OP(0x24): // INC H
|
|
OP(0x2c): // INC L
|
|
OP(0x3c): // INC A
|
|
OP_INC_R:
|
|
zR8(Opcode >> 3)++;
|
|
zF = (zF & CZ80_CF) | SZXYHV_inc[zR8(Opcode >> 3)];
|
|
RET(4)
|
|
|
|
{
|
|
uint16_t adr;
|
|
uint16_t res;
|
|
|
|
OP_INC_mIx:
|
|
adr = data->W + FETCH_BYTE_S;
|
|
CCnt -= 11;
|
|
goto OP_INC_m;
|
|
|
|
OP(0x34): // INC (HL)
|
|
adr = zHL;
|
|
|
|
OP_INC_m:
|
|
PRE_IO
|
|
READ_BYTE(adr, res)
|
|
res = (res + 1) & 0xFF;
|
|
WRITE_BYTE(adr, res)
|
|
zF = (zF & CZ80_CF) | SZXYHV_inc[res];
|
|
POST_IO
|
|
RET(11)
|
|
}
|
|
|
|
OP(0x05): // DEC B
|
|
OP(0x0d): // DEC C
|
|
OP(0x15): // DEC D
|
|
OP(0x1d): // DEC E
|
|
OP(0x25): // DEC H
|
|
OP(0x2d): // DEC L
|
|
OP(0x3d): // DEC A
|
|
OP_DEC_R:
|
|
zR8(Opcode >> 3)--;
|
|
zF = (zF & CZ80_CF) | SZXYHV_dec[zR8(Opcode >> 3)];
|
|
RET(4)
|
|
|
|
{
|
|
uint16_t adr;
|
|
uint16_t res;
|
|
|
|
OP_DEC_mIx:
|
|
adr = data->W + FETCH_BYTE_S;
|
|
CCnt -= 11;
|
|
goto OP_DEC_m;
|
|
|
|
OP(0x35): // DEC (HL)
|
|
adr = zHL;
|
|
|
|
OP_DEC_m:
|
|
PRE_IO
|
|
READ_BYTE(adr, res)
|
|
res = (res - 1) & 0xFF;
|
|
WRITE_BYTE(adr, res)
|
|
zF = (zF & CZ80_CF) | SZXYHV_dec[res];
|
|
POST_IO
|
|
RET(11)
|
|
}
|
|
|
|
{
|
|
uint8_t val;
|
|
uint16_t res;
|
|
|
|
// ADD
|
|
|
|
OP_ADD_mIx:
|
|
PRE_IO
|
|
READ_BYTE(data->W + FETCH_BYTE_S, val)
|
|
POST_IO
|
|
CCnt -= 11;
|
|
goto OP_ADD;
|
|
|
|
OP(0xc6): // ADD A,n
|
|
OP_ADD_imm:
|
|
val = FETCH_BYTE;
|
|
CCnt -= 3;
|
|
goto OP_ADD;
|
|
|
|
OP(0x86): // ADD A,(HL)
|
|
/* OP_ADD_mHL: */
|
|
PRE_IO
|
|
READ_BYTE(zHL, val)
|
|
POST_IO
|
|
CCnt -= 3;
|
|
goto OP_ADD;
|
|
|
|
OP_ADD_IxH:
|
|
val = data->B.H;
|
|
goto OP_ADD;
|
|
|
|
OP_ADD_IxL:
|
|
val = data->B.L;
|
|
goto OP_ADD;
|
|
|
|
OP(0x80): // ADD A,B
|
|
OP(0x81): // ADD A,C
|
|
OP(0x82): // ADD A,D
|
|
OP(0x83): // ADD A,E
|
|
OP(0x84): // ADD A,H
|
|
OP(0x85): // ADD A,L
|
|
OP(0x87): // ADD A,A
|
|
OP_ADD_R:
|
|
val = zR8(Opcode & 7);
|
|
|
|
OP_ADD:
|
|
// bench : maybe use src instead of zA in zF calculation
|
|
res = zA + val;
|
|
zF = SZXY[res & 0xFF] | // S/Z/X/Y flag
|
|
((zA ^ res ^ val) & CZ80_HF) | // H flag
|
|
(((val ^ zA ^ 0x80) & (val ^ res) & 0x80) >> 5) | // V flag
|
|
((res >> 8) & CZ80_CF); // C flag
|
|
zA = res;
|
|
RET(4)
|
|
|
|
// ADC
|
|
|
|
OP_ADC_mIx:
|
|
PRE_IO
|
|
READ_BYTE(data->W + FETCH_BYTE_S, val)
|
|
POST_IO
|
|
CCnt -= 11;
|
|
goto OP_ADC;
|
|
|
|
OP(0xce): // ADC A,n
|
|
OP_ADC_imm:
|
|
val = FETCH_BYTE;
|
|
CCnt -= 3;
|
|
goto OP_ADC;
|
|
|
|
OP(0x8e): // ADC A,(HL)
|
|
/* OP_ADC_mHL: */
|
|
PRE_IO
|
|
READ_BYTE(zHL, val)
|
|
POST_IO
|
|
CCnt -= 3;
|
|
goto OP_ADC;
|
|
|
|
OP_ADC_IxH:
|
|
val = data->B.H;
|
|
goto OP_ADC;
|
|
|
|
OP_ADC_IxL:
|
|
val = data->B.L;
|
|
goto OP_ADC;
|
|
|
|
OP(0x88): // ADC A,B
|
|
OP(0x89): // ADC A,C
|
|
OP(0x8a): // ADC A,D
|
|
OP(0x8b): // ADC A,E
|
|
OP(0x8c): // ADC A,H
|
|
OP(0x8d): // ADC A,L
|
|
OP(0x8f): // ADC A,A
|
|
OP_ADC_R:
|
|
val = zR8(Opcode & 7);
|
|
|
|
OP_ADC:
|
|
// bench : maybe use src instead of zA in zF calculation
|
|
res = (zA + val) + (zF & CZ80_CF);
|
|
zF = SZXY[res & 0xFF] | // S/Z/X/Y flag
|
|
((zA ^ res ^ val) & CZ80_HF) | // H flag
|
|
(((val ^ zA ^ 0x80) & (val ^ res) & 0x80) >> 5) | // V flag
|
|
((res >> 8) & CZ80_CF); // C flag
|
|
zA = res;
|
|
RET(4)
|
|
|
|
// SUB
|
|
|
|
OP_SUB_mIx:
|
|
PRE_IO
|
|
READ_BYTE(data->W + FETCH_BYTE_S, val)
|
|
POST_IO
|
|
CCnt -= 11;
|
|
goto OP_SUB;
|
|
|
|
OP(0xd6): // SUB A,n
|
|
OP_SUB_imm:
|
|
val = FETCH_BYTE;
|
|
CCnt -= 3;
|
|
goto OP_SUB;
|
|
|
|
OP(0x96): // SUB (HL)
|
|
/* OP_SUB_mHL: */
|
|
PRE_IO
|
|
READ_BYTE(zHL, val)
|
|
POST_IO
|
|
CCnt -= 3;
|
|
goto OP_SUB;
|
|
|
|
OP_SUB_IxH:
|
|
val = data->B.H;
|
|
goto OP_SUB;
|
|
|
|
OP_SUB_IxL:
|
|
val = data->B.L;
|
|
goto OP_SUB;
|
|
|
|
OP(0x90): // SUB B
|
|
OP(0x91): // SUB C
|
|
OP(0x92): // SUB D
|
|
OP(0x93): // SUB E
|
|
OP(0x94): // SUB H
|
|
OP(0x95): // SUB L
|
|
OP(0x97): // SUB A
|
|
OP_SUB_R:
|
|
val = zR8(Opcode & 7);
|
|
|
|
OP_SUB:
|
|
// bench : maybe use src instead of zA in zF calculation
|
|
res = zA - val;
|
|
zF = SZXY[res & 0xFF] | // S/Z/X/Y flag
|
|
((zA ^ res ^ val) & CZ80_HF) | // H flag
|
|
(((val ^ zA) & (zA ^ res) & 0x80) >> 5) | // V flag
|
|
((res >> 8) & CZ80_CF) | CZ80_NF; // C/N flag
|
|
zA = res;
|
|
RET(4)
|
|
|
|
// SBC
|
|
|
|
OP_SBC_mIx:
|
|
PRE_IO
|
|
READ_BYTE(data->W + FETCH_BYTE_S, val)
|
|
POST_IO
|
|
CCnt -= 11;
|
|
goto OP_SBC;
|
|
|
|
OP(0xde): // SBC A,n
|
|
OP_SBC_imm:
|
|
val = FETCH_BYTE;
|
|
CCnt -= 3;
|
|
goto OP_SBC;
|
|
|
|
OP(0x9e): // SBC A,(HL)
|
|
/* OP_SBC_mHL: */
|
|
PRE_IO
|
|
READ_BYTE(zHL, val)
|
|
POST_IO
|
|
CCnt -= 3;
|
|
goto OP_SBC;
|
|
|
|
OP_SBC_IxH:
|
|
val = data->B.H;
|
|
goto OP_SBC;
|
|
|
|
OP_SBC_IxL:
|
|
val = data->B.L;
|
|
goto OP_SBC;
|
|
|
|
OP(0x98): // SBC A,B
|
|
OP(0x99): // SBC A,C
|
|
OP(0x9a): // SBC A,D
|
|
OP(0x9b): // SBC A,E
|
|
OP(0x9c): // SBC A,H
|
|
OP(0x9d): // SBC A,L
|
|
OP(0x9f): // SBC A,A
|
|
OP_SBC_R:
|
|
val = zR8(Opcode & 7);
|
|
|
|
OP_SBC:
|
|
// bench : maybe use src instead of zA in zF calculation
|
|
res = zA - (val + (zF & CZ80_CF));
|
|
zF = SZXY[res & 0xFF] | // S/Z/X/Y flag
|
|
((zA ^ res ^ val) & CZ80_HF) | // H flag
|
|
(((val ^ zA) & (zA ^ res) & 0x80) >> 5) | // V flag
|
|
((res >> 8) & CZ80_CF) | CZ80_NF; // C/N flag
|
|
zA = res;
|
|
RET(4)
|
|
|
|
// CP
|
|
|
|
OP_CP_mIx:
|
|
PRE_IO
|
|
READ_BYTE(data->W + FETCH_BYTE_S, val)
|
|
POST_IO
|
|
CCnt -= 11;
|
|
goto OP_CP;
|
|
|
|
OP(0xfe): // CP n
|
|
OP_CP_imm:
|
|
val = FETCH_BYTE;
|
|
CCnt -= 3;
|
|
goto OP_CP;
|
|
|
|
OP(0xbe): // CP (HL)
|
|
/* OP_CP_mHL: */
|
|
PRE_IO
|
|
READ_BYTE(zHL, val)
|
|
POST_IO
|
|
CCnt -= 3;
|
|
goto OP_CP;
|
|
|
|
OP_CP_IxH:
|
|
val = data->B.H;
|
|
goto OP_CP;
|
|
|
|
OP_CP_IxL:
|
|
val = data->B.L;
|
|
goto OP_CP;
|
|
|
|
OP(0xb8): // CP B
|
|
OP(0xb9): // CP C
|
|
OP(0xba): // CP D
|
|
OP(0xbb): // CP E
|
|
OP(0xbc): // CP H
|
|
OP(0xbd): // CP L
|
|
OP(0xbf): // CP A
|
|
OP_CP_R:
|
|
val = zR8(Opcode & 7);
|
|
|
|
OP_CP:
|
|
// bench : maybe use src instead of zA in zF calculation
|
|
res = zA - val;
|
|
#if CZ80_DEBUG
|
|
zF = SZXY[res & 0xFF] | // S/Z/X/Y flag
|
|
((zA ^ res ^ val) & CZ80_HF) | // H flag
|
|
(((val ^ zA) & (zA ^ res) & 0x80) >> 5) | // V flag
|
|
((res >> 8) & CZ80_CF) | CZ80_NF; // C/N flag
|
|
#else
|
|
zF = (SZXY[res & 0xFF] & ~(CZ80_XF | CZ80_YF)) | // S/Z flag
|
|
(val & (CZ80_XF | CZ80_YF)) | // X/Y flag
|
|
((zA ^ res ^ val) & CZ80_HF) | // H flag
|
|
(((val ^ zA) & (zA ^ res) & 0x80) >> 5) | // V flag
|
|
((res >> 8) & CZ80_CF) | CZ80_NF; // C/N flag
|
|
#endif
|
|
RET(4)
|
|
}
|
|
|
|
// AND
|
|
|
|
{
|
|
uint8_t val;
|
|
|
|
OP(0xa6): // AND (HL)
|
|
/* OP_AND_mHL: */
|
|
PRE_IO
|
|
READ_BYTE(zHL, val)
|
|
POST_IO
|
|
goto OP_AND_;
|
|
|
|
OP(0xe6): // AND A,n
|
|
OP_AND_imm:
|
|
val = FETCH_BYTE;
|
|
|
|
OP_AND_:
|
|
zA = zA & val;
|
|
zF = SZXYP[zA] | CZ80_HF;
|
|
RET(7)
|
|
|
|
OP_AND_IxL:
|
|
val = data->B.L;
|
|
goto OP_AND;
|
|
|
|
OP_AND_IxH:
|
|
val = data->B.H;
|
|
goto OP_AND;
|
|
|
|
OP(0xa0): // AND B
|
|
OP(0xa1): // AND C
|
|
OP(0xa2): // AND D
|
|
OP(0xa3): // AND E
|
|
OP(0xa4): // AND H
|
|
OP(0xa5): // AND L
|
|
OP_AND_R:
|
|
val = zR8(Opcode & 7);
|
|
|
|
OP_AND:
|
|
zA = zA & val;
|
|
|
|
OP(0xa7): // AND A
|
|
OP_AND_A:
|
|
zF = SZXYP[zA] | CZ80_HF;
|
|
RET(4)
|
|
|
|
// XOR
|
|
|
|
OP(0xae): // XOR (HL)
|
|
/* OP_XOR_mHL: */
|
|
PRE_IO
|
|
READ_BYTE(zHL, val)
|
|
POST_IO
|
|
goto OP_XOR_;
|
|
|
|
OP(0xee): // XOR A,n
|
|
OP_XOR_imm:
|
|
val = FETCH_BYTE;
|
|
|
|
OP_XOR_:
|
|
zA = zA ^ val;
|
|
zF = SZXYP[zA];
|
|
RET(7)
|
|
|
|
OP_XOR_IxL:
|
|
val = data->B.L;
|
|
goto OP_XOR;
|
|
|
|
OP_XOR_IxH:
|
|
val = data->B.H;
|
|
goto OP_XOR;
|
|
|
|
OP(0xa8): // XOR B
|
|
OP(0xa9): // XOR C
|
|
OP(0xaa): // XOR D
|
|
OP(0xab): // XOR E
|
|
OP(0xac): // XOR H
|
|
OP(0xad): // XOR L
|
|
OP_XOR_R:
|
|
val = zR8(Opcode & 7);
|
|
|
|
OP_XOR:
|
|
zA = zA ^ val;
|
|
zF = SZXYP[zA];
|
|
RET(4)
|
|
|
|
OP(0xaf): // XOR A
|
|
OP_XOR_A:
|
|
zA = 0;
|
|
zF = SZXYP[zA];
|
|
RET(4)
|
|
|
|
// OR
|
|
|
|
OP(0xb6): // OR (HL)
|
|
/* OP_OR_mHL: */
|
|
PRE_IO
|
|
READ_BYTE(zHL, val)
|
|
POST_IO
|
|
goto OP_OR_;
|
|
|
|
OP(0xf6): // OR A,n
|
|
OP_OR_imm:
|
|
val = FETCH_BYTE;
|
|
|
|
OP_OR_:
|
|
zA = zA | val;
|
|
zF = SZXYP[zA];
|
|
RET(7)
|
|
|
|
OP_OR_IxL:
|
|
val = data->B.L;
|
|
goto OP_OR;
|
|
|
|
OP_OR_IxH:
|
|
val = data->B.H;
|
|
goto OP_OR;
|
|
|
|
OP(0xb0): // OR B
|
|
OP(0xb1): // OR C
|
|
OP(0xb2): // OR D
|
|
OP(0xb3): // OR E
|
|
OP(0xb4): // OR H
|
|
OP(0xb5): // OR L
|
|
OP_OR_R:
|
|
val = zR8(Opcode & 7);
|
|
|
|
OP_OR:
|
|
zA = zA | val;
|
|
|
|
OP(0xb7): // OR A
|
|
OP_OR_A:
|
|
zF = SZXYP[zA];
|
|
RET(4)
|
|
}
|
|
|
|
|
|
// MISC ARITHMETIC & CPU CONTROL
|
|
|
|
OP(0x27): // DAA
|
|
OP_DAA:
|
|
{
|
|
uint8_t _F;
|
|
uint8_t cf, nf, hf, lo, hi, diff;
|
|
|
|
_F = zF;
|
|
cf = _F & CZ80_CF;
|
|
nf = _F & CZ80_NF;
|
|
hf = _F & CZ80_HF;
|
|
lo = zA & 0x0F;
|
|
hi = zA >> 4;
|
|
|
|
if (cf)
|
|
{
|
|
diff = (lo <= 9 && !hf) ? 0x60 : 0x66;
|
|
}
|
|
else
|
|
{
|
|
if (lo >= 10)
|
|
{
|
|
diff = hi <= 8 ? 0x06 : 0x66;
|
|
}
|
|
else
|
|
{
|
|
if (hi >= 10)
|
|
{
|
|
diff = hf ? 0x66 : 0x60;
|
|
}
|
|
else
|
|
{
|
|
diff = hf ? 0x06 : 0x00;
|
|
}
|
|
}
|
|
}
|
|
if (nf) zA -= diff;
|
|
else zA += diff;
|
|
|
|
_F = SZXYP[zA] | (_F & CZ80_NF);
|
|
if (cf || (lo <= 9 ? hi >= 10 : hi >= 9)) _F |= CZ80_CF;
|
|
if (nf ? hf && lo <= 5 : lo >= 10) _F |= CZ80_HF;
|
|
zF = _F;
|
|
RET(4)
|
|
}
|
|
|
|
OP(0x2f): // CPL
|
|
OP_CPL:
|
|
zA ^= 0xFF;
|
|
zF = (zF & (CZ80_SF | CZ80_ZF | CZ80_PF | CZ80_CF)) |
|
|
CZ80_HF | CZ80_NF |
|
|
(zA & (CZ80_XF | CZ80_YF));
|
|
RET(4)
|
|
|
|
OP(0x37): // SCF
|
|
OP_SCF:
|
|
zF = (zF & (CZ80_SF | CZ80_ZF | CZ80_PF)) |
|
|
(zA & (CZ80_XF | CZ80_YF)) |
|
|
CZ80_CF;
|
|
RET(4)
|
|
|
|
OP(0x3f): // CCF
|
|
OP_CCF:
|
|
zF = ((zF & (CZ80_SF | CZ80_ZF | CZ80_PF | CZ80_CF)) |
|
|
((zF & CZ80_CF) << 4) |
|
|
(zA & (CZ80_XF | CZ80_YF))) ^
|
|
CZ80_CF;
|
|
RET(4)
|
|
|
|
OP(0x76): // HALT
|
|
OP_HALT:
|
|
// HALTED state
|
|
CPU->Status |= CZ80_HALTED;
|
|
// release remaining cycles...
|
|
CCnt = 0;
|
|
goto Cz80_Exec_Really_End;
|
|
|
|
OP(0xf3): // DI
|
|
OP_DI:
|
|
zIFF = 0;
|
|
#if CZ80_DEBUG
|
|
RET(4)
|
|
#else
|
|
CCnt -= 4;
|
|
// can't take interrupt after DI so we force next instruction execution
|
|
goto Cz80_Exec;
|
|
#endif
|
|
|
|
OP(0xfb): // EI
|
|
OP_EI:
|
|
zIFF = CZ80_IFF | (CZ80_IFF << 8);
|
|
#if CZ80_DEBUG
|
|
RET(4)
|
|
#else
|
|
// release remaining cycles...
|
|
CPU->CycleSup += CCnt - 4;
|
|
CCnt = 0;
|
|
// can't take interrupt after EI so we force next instruction execution
|
|
goto Cz80_Exec;
|
|
#endif
|
|
|
|
// 16 BITS ARITHMETIC
|
|
|
|
OP(0x03): // INC BC
|
|
OP_INC_BC:
|
|
zBC++;
|
|
RET(6)
|
|
|
|
OP(0x13): // INC DE
|
|
OP_INC_DE:
|
|
zDE++;
|
|
RET(6)
|
|
|
|
OP(0x23): // INC HL
|
|
OP_INC_xx:
|
|
data->W++;
|
|
RET(6)
|
|
|
|
OP(0x33): // INC SP
|
|
OP_INC_SP:
|
|
zSP++;
|
|
RET(6)
|
|
|
|
OP(0x0b): // DEC BC
|
|
OP_DEC_BC:
|
|
zBC--;
|
|
RET(6)
|
|
|
|
OP(0x1b): // DEC DE
|
|
OP_DEC_DE:
|
|
zDE--;
|
|
RET(6)
|
|
|
|
OP(0x2b): // DEC HL
|
|
OP_DEC_xx:
|
|
data->W--;
|
|
RET(6)
|
|
|
|
OP(0x3b): // DEC SP
|
|
OP_DEC_SP:
|
|
zSP--;
|
|
RET(6)
|
|
|
|
// ADD16
|
|
|
|
{
|
|
uint16_t src;
|
|
uint32_t res;
|
|
|
|
OP(0x39): // ADD xx,SP
|
|
OP_ADD16_xx_SP:
|
|
src = zSP;
|
|
goto OP_ADD16;
|
|
|
|
OP(0x29): // ADD xx,xx
|
|
OP_ADD16_xx_xx:
|
|
src = data->W;
|
|
goto OP_ADD16;
|
|
|
|
OP(0x09): // ADD xx,BC
|
|
OP_ADD16_xx_BC:
|
|
src = zBC;
|
|
goto OP_ADD16;
|
|
|
|
OP(0x19): // ADD xx,DE
|
|
OP_ADD16_xx_DE:
|
|
src = zDE;
|
|
|
|
OP_ADD16:
|
|
res = src + data->W;
|
|
#if CZ80_DEBUG
|
|
zF = (zF & (CZ80_SF | CZ80_ZF | CZ80_VF)) | // S/Z/V flag
|
|
(((src ^ data->W ^ res) >> 8) & CZ80_HF) | // H flag
|
|
((res >> 16) & CZ80_CF); // C flag
|
|
#else
|
|
zF = (zF & (CZ80_SF | CZ80_ZF | CZ80_VF)) | // S/Z/V flag
|
|
(((src ^ data->W ^ res) >> 8) & CZ80_HF) | // H flag
|
|
((res >> 8) & (CZ80_XF | CZ80_YF)) | // X/Y flag
|
|
((res >> 16) & CZ80_CF); // C flag
|
|
#endif
|
|
data->W = res;
|
|
RET(11)
|
|
}
|
|
|
|
// ROTATE
|
|
|
|
{
|
|
uint8_t A;
|
|
uint8_t F;
|
|
|
|
OP(0x07): // RLCA
|
|
OP_RLCA:
|
|
A = zA;
|
|
zA = (A << 1) | (A >> 7);
|
|
zF = (zF & (CZ80_SF | CZ80_ZF | CZ80_PF)) | // S/Z/P flag
|
|
(zA & (CZ80_XF | CZ80_YF | CZ80_CF)); // X/Y/C
|
|
RET(4)
|
|
|
|
OP(0x0f): // RRCA
|
|
OP_RRCA:
|
|
A = zA;
|
|
zA = (A >> 1) | (A << 7);
|
|
zF = (zF & (CZ80_SF | CZ80_ZF | CZ80_PF)) | // S/Z/P flag
|
|
(zA & (CZ80_XF | CZ80_YF)) | // X/Y flag
|
|
(A & CZ80_CF); // C flag
|
|
RET(4)
|
|
|
|
OP(0x17): // RLA
|
|
OP_RLA:
|
|
A = zA;
|
|
F = zF;
|
|
zA = (A << 1) | (F & CZ80_CF);
|
|
zF = (F & (CZ80_SF | CZ80_ZF | CZ80_PF)) | // S/Z/P flag
|
|
(zA & (CZ80_XF | CZ80_YF)) | // X/Y flag
|
|
(A >> 7); // C flag
|
|
RET(4)
|
|
|
|
OP(0x1f): // RRA
|
|
OP_RRA:
|
|
A = zA;
|
|
F = zF;
|
|
zA = (A >> 1) | (F << 7);
|
|
zF = (F & (CZ80_SF | CZ80_ZF | CZ80_PF)) | // S/Z/P flag
|
|
(zA & (CZ80_XF | CZ80_YF)) | // X/Y flag
|
|
(A & CZ80_CF); // C flag
|
|
RET(4)
|
|
}
|
|
|
|
// JUMP
|
|
|
|
OP(0xd2): // JP NC,nn
|
|
OP_JP_NC:
|
|
if (!(zF & CZ80_CF)) goto OP_JP;
|
|
PC += 2;
|
|
RET(10);
|
|
|
|
OP(0xda): // JP C,nn
|
|
OP_JP_C:
|
|
if (zF & CZ80_CF) goto OP_JP;
|
|
PC += 2;
|
|
RET(10);
|
|
|
|
OP(0xe2): // JP PO,nn
|
|
OP_JP_PO:
|
|
if (!(zF & CZ80_VF)) goto OP_JP;
|
|
PC += 2;
|
|
RET(10);
|
|
|
|
OP(0xea): // JP PE,nn
|
|
OP_JP_PE:
|
|
if (zF & CZ80_VF) goto OP_JP;
|
|
PC += 2;
|
|
RET(10);
|
|
|
|
OP(0xf2): // JP P,nn
|
|
OP_JP_P:
|
|
if (!(zF & CZ80_SF)) goto OP_JP;
|
|
PC += 2;
|
|
RET(10);
|
|
|
|
OP(0xfa): // JP M,nn
|
|
OP_JP_M:
|
|
if (zF & CZ80_SF) goto OP_JP;
|
|
PC += 2;
|
|
RET(10);
|
|
|
|
OP(0xca): // JP Z,nn
|
|
OP_JP_Z:
|
|
if (zF & CZ80_ZF) goto OP_JP;
|
|
PC += 2;
|
|
RET(10);
|
|
|
|
OP(0xc2): // JP NZ,nn
|
|
OP_JP_NZ:
|
|
if (!(zF & CZ80_ZF)) goto OP_JP;
|
|
PC += 2;
|
|
RET(10);
|
|
|
|
{
|
|
uint16_t newPC;
|
|
|
|
OP(0xc3): // JP nn
|
|
OP_JP:
|
|
newPC = GET_WORD;
|
|
SET_PC(newPC);
|
|
RET(10)
|
|
|
|
OP(0xe9): // JP (xx)
|
|
OP_JP_xx:
|
|
newPC = data->W;
|
|
SET_PC(newPC);
|
|
RET(4)
|
|
}
|
|
|
|
|
|
OP(0x38): // JR C,n
|
|
OP_JR_C:
|
|
if (zF & CZ80_CF) goto OP_JR;
|
|
PC++;
|
|
RET(7)
|
|
|
|
OP(0x30): // JR NC,n
|
|
OP_JR_NC:
|
|
if (!(zF & CZ80_CF)) goto OP_JR;
|
|
PC++;
|
|
RET(7)
|
|
|
|
OP(0x28): // JR Z,n
|
|
OP_JR_Z:
|
|
if (zF & CZ80_ZF) goto OP_JR;
|
|
PC++;
|
|
RET(7)
|
|
|
|
OP(0x20): // JR NZ,n
|
|
OP_JR_NZ:
|
|
if (!(zF & CZ80_ZF)) goto OP_JR;
|
|
PC++;
|
|
RET(7)
|
|
|
|
OP(0x10): // DJNZ n
|
|
OP_DJNZ:
|
|
CCnt--;
|
|
if (--zB) goto OP_JR;
|
|
PC++;
|
|
RET(9)
|
|
|
|
OP(0x18): // JR n
|
|
OP_JR:
|
|
{
|
|
uintptr_t adr;
|
|
|
|
adr = FETCH_BYTE_S;
|
|
// no rebase needed here...
|
|
PC += adr;
|
|
RET(12)
|
|
}
|
|
|
|
// CALL & RETURN
|
|
|
|
OP(0xd4): // CALL NC,nn
|
|
OP_CALL_NC:
|
|
if (!(zF & CZ80_CF)) goto OP_CALL;
|
|
PC += 2;
|
|
RET(10)
|
|
|
|
OP(0xdc): // CALL C,nn
|
|
OP_CALL_C:
|
|
if (zF & CZ80_CF) goto OP_CALL;
|
|
PC += 2;
|
|
RET(10)
|
|
|
|
OP(0xe4): // CALL PO,nn
|
|
OP_CALL_PO:
|
|
if (!(zF & CZ80_VF)) goto OP_CALL;
|
|
PC += 2;
|
|
RET(10)
|
|
|
|
OP(0xec): // CALL PE,nn
|
|
OP_CALL_PE:
|
|
if (zF & CZ80_VF) goto OP_CALL;
|
|
PC += 2;
|
|
RET(10)
|
|
|
|
OP(0xf4): // CALL P,nn
|
|
OP_CALL_P:
|
|
if (!(zF & CZ80_SF)) goto OP_CALL;
|
|
PC += 2;
|
|
RET(10)
|
|
|
|
OP(0xfc): // CALL M,nn
|
|
OP_CALL_M:
|
|
if (zF & CZ80_SF) goto OP_CALL;
|
|
PC += 2;
|
|
RET(10)
|
|
|
|
OP(0xcc): // CALL Z,nn
|
|
OP_CALL_Z:
|
|
if (zF & CZ80_ZF) goto OP_CALL;
|
|
PC += 2;
|
|
RET(10)
|
|
|
|
OP(0xc4): // CALL NZ,nn
|
|
OP_CALL_NZ:
|
|
if (!(zF & CZ80_ZF)) goto OP_CALL;
|
|
PC += 2;
|
|
RET(10)
|
|
|
|
OP(0xcd): // CALL nn
|
|
OP_CALL:
|
|
{
|
|
uint16_t oldRPC;
|
|
uint16_t newPC;
|
|
|
|
PRE_IO
|
|
FETCH_WORD(newPC);
|
|
oldRPC = PC;
|
|
PUSH_16(oldRPC);
|
|
SET_PC(newPC);
|
|
POST_IO
|
|
RET(17)
|
|
}
|
|
|
|
OP(0xd0): // RET NC
|
|
OP_RET_NC:
|
|
if (!(zF & CZ80_CF)) goto OP_RET_COND;
|
|
RET(5)
|
|
|
|
OP(0xd8): // RET C
|
|
OP_RET_C:
|
|
if (zF & CZ80_CF) goto OP_RET_COND;
|
|
RET(5)
|
|
|
|
OP(0xe0): // RET PO
|
|
OP_RET_PO:
|
|
if (!(zF & CZ80_VF)) goto OP_RET_COND;
|
|
RET(5)
|
|
|
|
OP(0xe8): // RET PE
|
|
OP_RET_PE:
|
|
if (zF & CZ80_VF) goto OP_RET_COND;
|
|
RET(5)
|
|
|
|
OP(0xf0): // RET P
|
|
OP_RET_P:
|
|
if (!(zF & CZ80_SF)) goto OP_RET_COND;
|
|
RET(5)
|
|
|
|
OP(0xf8): // RET M
|
|
OP_RET_M:
|
|
if (zF & CZ80_SF) goto OP_RET_COND;
|
|
RET(5)
|
|
|
|
OP(0xc0): // RET NZ
|
|
OP_RET_NZ:
|
|
if (!(zF & CZ80_ZF)) goto OP_RET_COND;
|
|
RET(5)
|
|
|
|
OP(0xc8): // RET Z
|
|
OP_RET_Z:
|
|
if (zF & CZ80_ZF) goto OP_RET_COND;
|
|
RET(5)
|
|
|
|
OP_RET_COND:
|
|
CCnt -= 7;
|
|
|
|
OP(0xc9): // RET
|
|
OP_RET:
|
|
{
|
|
uint16_t newPC;
|
|
|
|
PRE_IO
|
|
POP_16(newPC);
|
|
SET_PC(newPC);
|
|
POST_IO
|
|
RET(10)
|
|
}
|
|
|
|
|
|
OP(0xc7): // RST 0
|
|
OP(0xcf): // RST 1
|
|
OP(0xd7): // RST 2
|
|
OP(0xdf): // RST 3
|
|
OP(0xe7): // RST 4
|
|
OP(0xef): // RST 5
|
|
OP(0xf7): // RST 6
|
|
OP(0xff): // RST 7
|
|
OP_RST:
|
|
{
|
|
uint16_t src;
|
|
uint16_t newPC;
|
|
|
|
src = PC;
|
|
PUSH_16(src);
|
|
newPC = Opcode & 0x38;
|
|
SET_PC(newPC);
|
|
RET(11)
|
|
}
|
|
|
|
// INPUT & OUTPUT
|
|
|
|
{
|
|
uint16_t adr;
|
|
|
|
OP(0xd3): // OUT (n),A
|
|
OP_OUT_mN_A:
|
|
adr = (zA << 8) | FETCH_BYTE;
|
|
OUT(adr, zA)
|
|
RET(11)
|
|
|
|
OP(0xdb): // IN A,(n)
|
|
OP_IN_A_mN:
|
|
adr = (zA << 8) | FETCH_BYTE;
|
|
IN(adr, zA)
|
|
RET(11)
|
|
}
|
|
|
|
// PREFIXE
|
|
|
|
OP(0xcb): // CB PREFIXE (BIT & SHIFT INSTRUCTIONS)
|
|
/* CB_PREFIXE: */
|
|
Opcode = FETCH_BYTE;
|
|
#include "cz80_opcb.inc"
|
|
|
|
OP(0xed): // ED PREFIXE
|
|
ED_PREFIXE:
|
|
CCnt -= 4;
|
|
Opcode = FETCH_BYTE;
|
|
#include "cz80_oped.inc"
|
|
|
|
OP(0xdd): // DD PREFIXE (IX)
|
|
DD_PREFIXE:
|
|
data = pzIX;
|
|
goto XY_PREFIXE;
|
|
|
|
OP(0xfd): // FD PREFIXE (IY)
|
|
FD_PREFIXE:
|
|
data = pzIY;
|
|
|
|
XY_PREFIXE:
|
|
CCnt -= 4;
|
|
Opcode = FETCH_BYTE;
|
|
#include "cz80_opxy.inc"
|
|
|
|
#if CZ80_USE_JUMPTABLE
|
|
#else
|
|
}
|
|
#endif
|
|
|