Slide 132
Slide 132 text
長谷川智希 @tomzoh
続CPUとは何か - ハードウェアエミュレータから見たCPU
全命令を実装する
• 左のリストはZ80の命令 0x00 〜 0xff まで
• 256個の case 文 1,300行ぐらい
• 実際は少し工夫してるのでもう少し少ない
• 工夫しない方が速いことも
• 全命令だと3,000行弱
30
void OpCode::execute(uint8_t opCode){
if ((opCode >> 6) == 0b01 && (opCode & 0b00111000) != 0b00110000 && (opCode & 0b00000111) != 0b00000110){
// ld r, r'
Log::execute(this->_cpu, opCode, "ld r, r'");
uint8_t *reg = this->targetRegister(opCode, 3);
uint8_t *reg_dash = this->targetRegister(opCode, 0);
*reg = *reg_dash;
Log::dump_registers(this->_cpu);
return;
}
switch (opCode){
case 0x00: // nop
Log::execute(this->_cpu, opCode, "nop");
break;
case 0x01: // ld bc, nn
Log::execute(this->_cpu, opCode, "ld bc, nn");
this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
this->_cpu->special_registers.pc += 2;
break;
case 0x02: { // ld (bc), a
Log::execute(this->_cpu, opCode, "ld (bc), a");
Mcycle::m3(this->_cpu, this->_cpu->registers.bc(), this->_cpu->registers.a);
break;
}
case 0x03: // inc bc
Log::execute(this->_cpu, opCode, "inc bc");
this->_cpu->registers.bc(this->_cpu->registers.bc() + 1);
break;
case 0x04: // inc r
case 0x0C:
case 0x14:
case 0x1C:
case 0x24:
case 0x2C:
case 0x3C: {
Log::execute(this->_cpu, opCode, "inc r");
uint8_t *reg = this->targetRegister(opCode, 3);
this->setFlagsByIncrement(*reg);
(*reg)++;
break;
}
case 0x05: // dec r
case 0x0D:
case 0x15:
case 0x1D:
case 0x25:
case 0x2D:
case 0x3D: {
Log::execute(this->_cpu, opCode, "dec r");
uint8_t *reg = this->targetRegister(opCode, 3);
this->setFlagsByDecrement(*reg);
(*reg)--;
break;
}
case 0x06: // ld r, n
case 0x0e:
case 0x16:
case 0x1e:
case 0x26:
case 0x2e:
case 0x3e: {
Log::execute(this->_cpu, opCode, "ld r, n");
uint8_t* reg = this->targetRegister(opCode, 3);
*reg = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
break;
}
case 0x07: { // rlca
Log::execute(this->_cpu, opCode, "rlca");
bool carry_bit = (this->_cpu->registers.a >> 7);
this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_bit;
this->_cpu->registers.FC_Carry = carry_bit;
this->_cpu->registers.FH_HalfCarry = false;
this->_cpu->registers.FN_Subtract = false;
break;
}
case 0x08: { // ex af, af'
Log::execute(this->_cpu, opCode, "ex af, af'");
uint16_t af = this->_cpu->registers.af();
this->_cpu->registers.af(this->_cpu->registers_alternate.af());
this->_cpu->registers_alternate.af(af);
break;
}
case 0x09: // add hl, rr
case 0x19:
case 0x29:
case 0x39: {
Log::execute(this->_cpu, opCode, "add hl, rr");
uint16_t value;
switch (opCode){ // NOLINT(hicpp-multiway-paths-covered)
case 0x09: value = this->_cpu->registers.bc(); break;
case 0x19: value = this->_cpu->registers.de(); break;
case 0x29: value = this->_cpu->registers.hl(); break;
case 0x39: value = this->_cpu->special_registers.sp; break;
}
this->setFlagsByAdd16(this->_cpu->registers.hl(), value);
this->_cpu->registers.hl(this->_cpu->registers.hl() + value);
break;
}
case 0x0A: // ld a,(bc)
Log::execute(this->_cpu, opCode, "ld a,(bc)");
this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.bc());
break;
case 0x0B: // dec bc
Log::execute(this->_cpu, opCode, "dec bc");
this->_cpu->registers.bc(this->_cpu->registers.bc() - 1);
break;
case 0x0F: { // rrca
Log::execute(this->_cpu, opCode, "rrca");
bool carry_bit = ((this->_cpu->registers.a & 1) > 0);
this->_cpu->registers.a = (this->_cpu->registers.a >> 1) + ((this->_cpu->registers.a & 1) << 7);
this->_cpu->registers.FH_HalfCarry = false;
this->_cpu->registers.FN_Subtract = false;
this->_cpu->registers.FC_Carry = carry_bit;
break;
}
case 0x10: { // djnz n
Log::execute(this->_cpu, opCode, "djnz n");
this->_cpu->registers.b--;
if (this->_cpu->registers.b != 0){
auto diff = (int8_t)Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
this->_cpu->special_registers.pc += diff;
} else {
this->_cpu->special_registers.pc++;
}
break;
}
case 0x11: // ld de, nn
Log::execute(this->_cpu, opCode, "ld de, nn");
this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
this->_cpu->special_registers.pc += 2;
break;
case 0x12: // ld (de),a
Log::execute(this->_cpu, opCode, "ld (de),a");
Mcycle::m3(this->_cpu, this->_cpu->registers.de(), this->_cpu->registers.a);
break;
case 0x13: // inc de
Log::execute(this->_cpu, opCode, "inc de");
this->_cpu->registers.de(this->_cpu->registers.de() + 1);
break;
case 0x17: { // rla
Log::execute(this->_cpu, opCode, "rla");
bool carry_flg = this->_cpu->registers.FC_Carry;
this->_cpu->registers.FC_Carry = this->_cpu->registers.a >> 7;
this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_flg;
this->_cpu->registers.FN_Subtract = false;
this->_cpu->registers.FH_HalfCarry = false;
break;
}
case 0x18: { // jr n
Log::execute(this->_cpu, opCode, "jr n");
auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
this->_cpu->special_registers.pc++;
this->_cpu->special_registers.pc += diff;
break;
}
case 0x1A: // ld a,(de)
Log::execute(this->_cpu, opCode, "ld a,(de)");
this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.de());
break;
case 0x1B: // dec de
Log::execute(this->_cpu, opCode, "dec de");
this->_cpu->registers.de(this->_cpu->registers.de() - 1);
break;
case 0x1F: { // rra
Log::execute(this->_cpu, opCode, "rra");
bool carry_flg = this->_cpu->registers.FC_Carry;
this->_cpu->registers.FC_Carry = this->_cpu->registers.a & 1;
this->_cpu->registers.a = (this->_cpu->registers.a >> 1) | (carry_flg << 7);
this->_cpu->registers.FN_Subtract = false;
this->_cpu->registers.FH_HalfCarry = false;
break;
}
case 0x20: // jr nz, n
Log::execute(this->_cpu, opCode, "jr nz, n");
if (! this->_cpu->registers.FZ_Zero){
auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
this->_cpu->special_registers.pc++;
this->_cpu->special_registers.pc += diff;
} else {
this->_cpu->special_registers.pc++;
}
break;
case 0x21: // ld hl, nn
Log::execute(this->_cpu, opCode, "ld hl, nn");
this->_cpu->registers.hl(
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8)
);
this->_cpu->special_registers.pc += 2;
break;
case 0x22: { // ld (nn), hl
Log::execute(this->_cpu, opCode, "ld (nn), hl");
uint16_t addr =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
Mcycle::m3(this->_cpu, addr, this->_cpu->registers.l);
Mcycle::m3(this->_cpu, addr + 1, this->_cpu->registers.h);
this->_cpu->special_registers.pc += 2;
break;
}
case 0x23: // inc hl
Log::execute(this->_cpu, opCode, "inc hl");
this->_cpu->registers.hl(this->_cpu->registers.hl() + 1);
break;
case 0x27: { // daa
Log::execute(this->_cpu, opCode, "daa");
uint8_t cr = 0;
if ((this->_cpu->registers.a & 0x0f) > 0x09 || this->_cpu->registers.FH_HalfCarry){
cr += 0x06;
}
if (this->_cpu->registers.a > 0x99 || this->_cpu->registers.FC_Carry){
cr += 0x60;
this->_cpu->registers.FC_Carry = true;
}
if (this->_cpu->registers.FN_Subtract){
this->_cpu->registers.FH_HalfCarry =
this->_cpu->registers.FH_HalfCarry &&
(this->_cpu->registers.a & 0x0f) < 0x06;
this->_cpu->registers.a -= cr;
} else {
this->_cpu->registers.FH_HalfCarry = (this->_cpu->registers.a & 0x0f) > 0x09;
this->_cpu->registers.a += cr;
}
this->_cpu->registers.FS_Sign = this->_cpu->registers.a >> 7;
this->_cpu->registers.FZ_Zero = this->_cpu->registers.a == 0;
this->_cpu->registers.FPV_ParityOverflow = (OpCode::count1(this->_cpu->registers.a) % 2 == 0);
break;
}
case 0x28: // jr z, n
Log::execute(this->_cpu, opCode, "jr z, n");
if (this->_cpu->registers.FZ_Zero){
auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
this->_cpu->special_registers.pc++;
this->_cpu->special_registers.pc += diff;
} else {
this->_cpu->special_registers.pc++;
}
break;
case 0x2A: { // ld hl, (nn)
Log::execute(this->_cpu, opCode, "ld hl, (nn)");
uint16_t addr =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
this->_cpu->special_registers.pc += 2;
this->_cpu->registers.l = Mcycle::m2(this->_cpu, addr);
this->_cpu->registers.h = Mcycle::m2(this->_cpu, addr + 1);
Log::dump_registers(this->_cpu);
break;
}
case 0x2B: // dec hl
Log::execute(this->_cpu, opCode, "dec hl");
this->_cpu->registers.hl(this->_cpu->registers.hl() - 1);
break;
case 0x2F: // cpl
Log::execute(this->_cpu, opCode, "cpl");
this->_cpu->registers.a ^= 0xff;
this->_cpu->registers.FN_Subtract = true;
this->_cpu->registers.FH_HalfCarry = true;
break;
case 0x30: // jr nc, n
Log::execute(this->_cpu, opCode, "jr nc, n");
if (!this->_cpu->registers.FC_Carry){
auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
this->_cpu->special_registers.pc++;
this->_cpu->special_registers.pc += diff;
} else {
this->_cpu->special_registers.pc++;
}
break;
case 0x31: // ld sp, nn
Log::execute(this->_cpu, opCode, "ld sp, nn");
this->_cpu->special_registers.sp =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
this->_cpu->special_registers.pc += 2;
break;
case 0x32: { // ld (nn), a
Log::execute(this->_cpu, opCode, "ld (nn), a");
uint16_t addr =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
Mcycle::m3(this->_cpu, addr, this->_cpu->registers.a);
this->_cpu->special_registers.pc += 2;
break;
}
case 0x33: // inc sp
Log::execute(this->_cpu, opCode, "inc sp");
this->_cpu->special_registers.sp++;
break;
case 0x34: { // inc (hl)
Log::execute(this->_cpu, opCode, "inc (hl)");
uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
this->setFlagsByIncrement(value);
Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value + 1);
break;
}
case 0x35: { // dec (hl)
Log::execute(this->_cpu, opCode, "dec (hl)");
uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
this->setFlagsByDecrement(value);
Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value - 1);
break;
}
case 0x36: // ld (hl), n
Log::execute(this->_cpu, opCode, "ld (hl), n");
Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
this->_cpu->special_registers.pc++;
break;
case 0x37: // scf
Log::execute(this->_cpu, opCode, "scf");
this->_cpu->registers.FC_Carry = true;
this->_cpu->registers.FN_Subtract = false;
this->_cpu->registers.FH_HalfCarry = false;
break;
case 0x38: // jr c, n
Log::execute(this->_cpu, opCode, "jr c, n");
if (this->_cpu->registers.FC_Carry) {
auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
this->_cpu->special_registers.pc++;
this->_cpu->special_registers.pc += diff;
} else {
this->_cpu->special_registers.pc++;
}
break;
case 0x3A: { // ld a, (nn)
Log::execute(this->_cpu, opCode, "ld a, (nn)");
uint16_t addr =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
this->_cpu->special_registers.pc += 2;
this->_cpu->registers.a = Mcycle::m2(this->_cpu, addr);
Log::dump_registers(this->_cpu);
break;
}
case 0x3B: // dec sp
Log::execute(this->_cpu, opCode, "dec sp");
this->_cpu->special_registers.sp--;
break;
case 0x3F: { // ccf
Log::execute(this->_cpu, opCode, "ccf");
bool saved_carry = this->_cpu->registers.FC_Carry;
this->_cpu->registers.FC_Carry = !this->_cpu->registers.FC_Carry;
this->_cpu->registers.FN_Subtract = false;
this->_cpu->registers.FH_HalfCarry = saved_carry;
break;
}
case 0x46: // ld r, (hl)
case 0x4E:
case 0x56:
case 0x5E:
case 0x66:
case 0x6E: {
Log::execute(this->_cpu, opCode, "ld r, (hl)");
uint8_t *reg = this->targetRegister(opCode, 3);
*reg = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
break;
}
case 0x70: // ld (hl), r
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x77:
Log::execute(this->_cpu, opCode, "ld (hl), r");
Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), *(this->targetRegister(opCode, 0)));
break;
case 0x76: // halt
Log::execute(this->_cpu, opCode, "halt");
this->_cpu->halt = true;
break;
case 0x7E: // ld a,(hl)
Log::execute(this->_cpu, opCode, "ld a,(hl)");
this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
break;
case 0x80: // add a, r
case 0x81:
case 0x82:
case 0x83:
case 0x84:
case 0x85:
case 0x87: {
Log::execute(this->_cpu, opCode, "add a, r");
uint8_t* reg = this->targetRegister(opCode, 0);
this->setFlagsByAddition(this->_cpu->registers.a, *reg, 0);
this->_cpu->registers.a += *reg;
break;
}
case 0x86: { // add a, (hl)
Log::execute(this->_cpu, opCode, "add a, (hl)");
uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
this->_cpu->registers.a += value;
break;
}
case 0x88: // adc a, r
case 0x89:
case 0x8A:
case 0x8B:
case 0x8C:
case 0x8D:
case 0x8F: {
Log::execute(this->_cpu, opCode, "adc a, r");
uint8_t* reg = this->targetRegister(opCode, 0);
uint8_t carry = this->_cpu->registers.carry_by_val();
this->setFlagsByAddition(this->_cpu->registers.a, *reg, carry);
this->_cpu->registers.a += *reg + carry;
break;
}
case 0x8E: { // adc a, (hl)
Log::execute(this->_cpu, opCode, "adc a, (hl)");
uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
uint8_t carry = this->_cpu->registers.carry_by_val();
this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
this->_cpu->registers.a += value + carry;
break;
}
case 0x90: // sub r
case 0x91:
case 0x92:
case 0x93:
case 0x94:
case 0x95:
case 0x97: {
Log::execute(this->_cpu, opCode, "sub r");
uint8_t* reg = this->targetRegister(opCode, 0);
this->setFlagsBySubtract(this->_cpu->registers.a, *reg, 0);
this->_cpu->registers.a -= *reg;
break;
}
case 0x96: { // sub (hl)
Log::execute(this->_cpu, opCode, "sub (hl)");
uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
this->_cpu->registers.a -= value;
break;
}
case 0x98: // sbc a, r
case 0x99:
case 0x9A:
case 0x9B:
case 0x9C:
case 0x9D:
case 0x9F: {
Log::execute(this->_cpu, opCode, "sbc a, r");
uint8_t* reg = this->targetRegister(opCode, 0);
uint8_t carry = this->_cpu->registers.carry_by_val();
this->setFlagsBySubtract(this->_cpu->registers.a, *reg, carry);
this->_cpu->registers.a -= *reg + carry;
break;
}
case 0x9E: { // sbc a,(hl)
Log::execute(this->_cpu, opCode, "sbc a,(hl)");
uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
uint8_t carry = this->_cpu->registers.carry_by_val();
this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
this->_cpu->registers.a -= value + carry;
break;
}
case 0xA0: // and r
case 0xA1:
case 0xA2:
case 0xA3:
case 0xA4:
case 0xA5:
case 0xA7: {
Log::execute(this->_cpu, opCode, "and r");
uint8_t* reg = this->targetRegister(opCode, 0);
this->_cpu->registers.a &= *reg;
this->setFlagsByLogical(true);
break;
}
case 0xA6: // and (hl)
Log::execute(this->_cpu, opCode, "and (hl)");
this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
this->setFlagsByLogical(true);
break;
case 0xA8: // xor r
case 0xA9:
case 0xAA:
case 0xAB:
case 0xAC:
case 0xAD:
case 0xAF: {
Log::execute(this->_cpu, opCode, "xor r");
uint8_t* reg = this->targetRegister(opCode, 0);
this->_cpu->registers.a ^= *reg;
this->setFlagsByLogical(false);
break;
}
case 0xAE: // xor (hl)
Log::execute(this->_cpu, opCode, "xor (hl)");
this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
this->setFlagsByLogical(false);
break;
case 0xB0: // or r
case 0xB1:
case 0xB2:
case 0xB3:
case 0xB4:
case 0xB5:
case 0xB7: {
Log::execute(this->_cpu, opCode, "or r");
uint8_t* reg = this->targetRegister(opCode, 0);
this->_cpu->registers.a |= *reg;
this->setFlagsByLogical(false);
break;
}
case 0xB6: // or (hl)
Log::execute(this->_cpu, opCode, "or (hl)");
this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
this->setFlagsByLogical(false);
break;
case 0xB8: // cp r
case 0xB9:
case 0xBA:
case 0xBB:
case 0xBC:
case 0xBD:
case 0xBF:
Log::execute(this->_cpu, opCode, "cp r");
this->setFlagsBySubtract(this->_cpu->registers.a, *(this->targetRegister(opCode, 0)), 0);
break;
case 0xBE: { // cp (hl)
Log::execute(this->_cpu, opCode, "cp (hl)");
uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
break;
}
case 0xC0: // ret nz
Log::execute(this->_cpu, opCode, "ret nz");
if (!this->_cpu->registers.FZ_Zero) {
executeRet();
}
break;
case 0xC1: // pop bc
Log::execute(this->_cpu, opCode, "pop bc");
this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
this->_cpu->special_registers.sp += 2;
Log::dump_registers(this->_cpu);
break;
case 0xC2: // jp nz, nn
Log::execute(this->_cpu, opCode, "jp nz, nn");
if (!this->_cpu->registers.FZ_Zero) {
this->_cpu->special_registers.pc =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xC3: // jp nn
Log::execute(this->_cpu, opCode, "jp nn");
this->_cpu->special_registers.pc =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
break;
case 0xC4: // call nz, nn
Log::execute(this->_cpu, opCode, "call nz, nn");
if (!this->_cpu->registers.FZ_Zero) {
this->executeCall();
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xC5: // push bc
Log::execute(this->_cpu, opCode, "push bc");
this->_cpu->special_registers.sp--;
Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.b);
this->_cpu->special_registers.sp--;
Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.c);
Log::dump_registers(this->_cpu);
break;
case 0xC6: { // add a, n
Log::execute(this->_cpu, opCode, "add a, n");
uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
this->_cpu->registers.a += value;
break;
}
case 0xC7: // rst n (n = 0 - 7)
case 0xCF:
case 0xD7:
case 0xDF:
case 0xE7:
case 0xEF:
case 0xF7:
case 0xFF:
Log::execute(this->_cpu, opCode, "rst n (n = 0 - 7)");
this->_cpu->special_registers.sp--;
Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc >> 8);
this->_cpu->special_registers.sp--;
Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc & 0xff);
this->_cpu->special_registers.pc = (opCode & 0b00111000);
break;
case 0xC8: // ret z
Log::execute(this->_cpu, opCode, "ret z");
if (this->_cpu->registers.FZ_Zero) {
executeRet();
}
break;
case 0xC9: // ret
Log::execute(this->_cpu, opCode, "ret");
executeRet();
break;
case 0xCA: // jp z, nn
Log::execute(this->_cpu, opCode, "jp z, nn");
if (this->_cpu->registers.FZ_Zero) {
this->_cpu->special_registers.pc =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xCB: { // BITS
Log::execute(this->_cpu, opCode, "BITS");
uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
executeCb(opcode);
break;
}
case 0xCC: // call z, nn
Log::execute(this->_cpu, opCode, "call z, nn");
if (this->_cpu->registers.FZ_Zero) {
this->executeCall();
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xCD: { // call nn
Log::execute(this->_cpu, opCode, "call nn");
this->executeCall();
break;
}
case 0xCE: { // adc a, n
Log::execute(this->_cpu, opCode, "adc a, n");
uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
uint8_t carry = this->_cpu->registers.carry_by_val();
this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
this->_cpu->registers.a += value + carry;
break;
}
case 0xD0: // ret nc
Log::execute(this->_cpu, opCode, "ret nc");
if (!this->_cpu->registers.FC_Carry) {
executeRet();
}
break;
case 0xD1: // pop de
Log::execute(this->_cpu, opCode, "pop de");
this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
this->_cpu->special_registers.sp += 2;
Log::dump_registers(this->_cpu);
break;
case 0xD2: // jp nc, nn
Log::execute(this->_cpu, opCode, "jp nc, nn");
if (!this->_cpu->registers.FC_Carry) {
this->_cpu->special_registers.pc =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xD3: { // out (n),a
Log::execute(this->_cpu, opCode, "out (n),a");
uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc += 1;
Mcycle::out(this->_cpu, port, this->_cpu->registers.a, this->_cpu->registers.a);
break;
}
case 0xD4: // call nc, nn
Log::execute(this->_cpu, opCode, "call nc, nn");
if (!this->_cpu->registers.FC_Carry) {
this->executeCall();
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xD5: // push de
Log::execute(this->_cpu, opCode, "push de");
this->_cpu->special_registers.sp--;
Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.d);
this->_cpu->special_registers.sp--;
Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.e);
Log::dump_registers(this->_cpu);
break;
case 0xD6: { // sub n
Log::execute(this->_cpu, opCode, "sub n");
uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
this->_cpu->registers.a -= value;
break;
}
case 0xD8: // ret c
Log::execute(this->_cpu, opCode, "ret c");
if (this->_cpu->registers.FC_Carry) {
executeRet();
}
break;
case 0xD9: { // exx
Log::execute(this->_cpu, opCode, "exx");
uint16_t temp;
temp = this->_cpu->registers.bc();
this->_cpu->registers.bc(this->_cpu->registers_alternate.bc());
this->_cpu->registers_alternate.bc(temp);
temp = this->_cpu->registers.de();
this->_cpu->registers.de(this->_cpu->registers_alternate.de());
this->_cpu->registers_alternate.de(temp);
temp = this->_cpu->registers.hl();
this->_cpu->registers.hl(this->_cpu->registers_alternate.hl());
this->_cpu->registers_alternate.hl(temp);
break;
}
case 0xDA: // jp c, nn
Log::execute(this->_cpu, opCode, "jp c, nn");
if (this->_cpu->registers.FC_Carry) {
this->_cpu->special_registers.pc =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xDB: { // in a, (n)
Log::execute(this->_cpu, opCode, "in a, (n)");
uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
this->_cpu->registers.a = Mcycle::in(this->_cpu, port, this->_cpu->registers.a);
break;
}
case 0xDC: // call c, nn
Log::execute(this->_cpu, opCode, "call c, nn");
if (this->_cpu->registers.FC_Carry) {
this->executeCall();
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xDD: { // IX
Log::execute(this->_cpu, opCode, "IX");
uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
executeDd(opcode);
break;
}
case 0xDE: { // sbc a, n
Log::execute(this->_cpu, opCode, "sbc a, n");
uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
uint8_t carry = this->_cpu->registers.carry_by_val();
this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
this->_cpu->registers.a -= value + carry;
break;
}
case 0xE0: // ret po
Log::execute(this->_cpu, opCode, "ret po");
if (! this->_cpu->registers.FPV_ParityOverflow){
executeRet();
}
break;
case 0xE1: // pop hl
Log::execute(this->_cpu, opCode, "pop hl");
this->_cpu->registers.hl(
Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8)
);
this->_cpu->special_registers.sp += 2;
Log::dump_registers(this->_cpu);
break;
case 0xE2: // jp po, nn
Log::execute(this->_cpu, opCode, "jp po, nn");
if (! this->_cpu->registers.FPV_ParityOverflow){
this->_cpu->special_registers.pc =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xE3: { // ex (sp), hl
Log::execute(this->_cpu, opCode, "ex (sp), hl");
uint16_t mem_value =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8);
uint16_t temp_hl = this->_cpu->registers.hl();
this->_cpu->registers.hl(mem_value);
Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, temp_hl & 0xff);
Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp + 1, temp_hl >> 8);
break;
}
case 0xE4: // call po, nn
Log::execute(this->_cpu, opCode, "call po, nn");
if (! this->_cpu->registers.FPV_ParityOverflow) {
this->executeCall();
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xE5: // push hl
Log::execute(this->_cpu, opCode, "push hl");
this->_cpu->special_registers.sp--;
Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() >> 8);
this->_cpu->special_registers.sp--;
Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() & 0xff);
Log::dump_registers(this->_cpu);
break;
case 0xE6: // and n
Log::execute(this->_cpu, opCode, "and n");
this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
this->setFlagsByLogical(true);
break;
case 0xE8: // ret pe
Log::execute(this->_cpu, opCode, "ret pe");
if (this->_cpu->registers.FPV_ParityOverflow) {
executeRet();
}
break;
case 0xE9: // jp (hl)
Log::execute(this->_cpu, opCode, "jp (hl)");
this->_cpu->special_registers.pc = this->_cpu->registers.hl();
break;
case 0xEA: // jp pe, nn
Log::execute(this->_cpu, opCode, "jp pe, nn");
if (this->_cpu->registers.FPV_ParityOverflow) {
this->_cpu->special_registers.pc =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xEB: { // ex de,hl
Log::execute(this->_cpu, opCode, "ex de,hl");
uint16_t de = this->_cpu->registers.de();
this->_cpu->registers.de(this->_cpu->registers.hl());
this->_cpu->registers.hl(de);
break;
}
case 0xEC: // call pe, nn
Log::execute(this->_cpu, opCode, "call pe, nn");
if (this->_cpu->registers.FPV_ParityOverflow) {
this->executeCall();
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xED: { // EXTD
Log::execute(this->_cpu, opCode, "EXTD");
uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
executeEd(opcode);
break;
}
case 0xEE: // xor n
Log::execute(this->_cpu, opCode, "xor n");
this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
this->setFlagsByLogical(false);
break;
case 0xF0: // ret p
Log::execute(this->_cpu, opCode, "ret p");
if (! this->_cpu->registers.FS_Sign){
executeRet();
}
break;
case 0xF1: // pop af
Log::execute(this->_cpu, opCode, "pop af");
this->_cpu->registers.f(Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp));
this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
this->_cpu->special_registers.sp += 2;
Log::dump_registers(this->_cpu);
break;
case 0xF2: // jp p, nn
Log::execute(this->_cpu, opCode, "jp p, nn");
if (! this->_cpu->registers.FS_Sign){
this->_cpu->special_registers.pc =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xF3: // di
Log::execute(this->_cpu, opCode, "di");
this->_cpu->waitingDI = 1;
break;
case 0xF4: // call p, nn
Log::execute(this->_cpu, opCode, "call p, nn");
if (! this->_cpu->registers.FS_Sign) {
this->executeCall();
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xF5: // push af
Log::execute(this->_cpu, opCode, "push af");
this->_cpu->special_registers.sp--;
Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.a);
this->_cpu->special_registers.sp--;
Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.f());
Log::dump_registers(this->_cpu);
break;
case 0xF6: // or n
Log::execute(this->_cpu, opCode, "or n");
this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
this->setFlagsByLogical(false);
break;
case 0xF8: // ret m
Log::execute(this->_cpu, opCode, "ret m");
if (this->_cpu->registers.FS_Sign){
executeRet();
}
break;
case 0xF9: // ld sp,hl
Log::execute(this->_cpu, opCode, "ld sp,hl");
this->_cpu->special_registers.sp = this->_cpu->registers.hl();
break;
case 0xFA: // jp m, nn
Log::execute(this->_cpu, opCode, "jp m, nn");
if (this->_cpu->registers.FS_Sign){
this->_cpu->special_registers.pc =
Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xFB: // ei
Log::execute(this->_cpu, opCode, "ei");
this->_cpu->waitingEI = 2;
break;
case 0xFC: // call m, nn
Log::execute(this->_cpu, opCode, "call m, nn");
if (this->_cpu->registers.FS_Sign){
this->executeCall();
} else {
this->_cpu->special_registers.pc += 2;
}
break;
case 0xFD: { // IY
Log::execute(this->_cpu, opCode, "IY");
uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
this->_cpu->special_registers.pc++;
executeFd(opcode);
break;
}
case 0xFE: { // cp n
Log::execute(this->_cpu, opCode, "cp n");
this->setFlagsBySubtract(this->_cpu->registers.a, Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc), 0);
this->_cpu->special_registers.pc++;
break;
}
default:
char error[100];
sprintf(error, "Invalid op code: %02x", opCode);
Log::error(this->_cpu, error);
throw std::runtime_error(error);
}
}