diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index fc849b6fc..1ae99b88b 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -91,6 +91,19 @@ struct MicroOp { AssembleAF, DisassembleAF, + And, + Or, + Xor, + + TestNZ, + TestZ, + TestNC, + TestC, + TestPO, + TestPE, + TestP, + TestM, + None } type; void *source; @@ -115,7 +128,7 @@ template class Processor: public MicroOpScheduler { RegisterPair bc_, de_, hl_; RegisterPair afDash_, bcDash_, deDash_, hlDash_; RegisterPair ix_, iy_, pc_, sp_; - uint8_t carry_flag_, sign_result_, bit5_result_, half_carry_flag_, bit3_result_, parity_overflow_flag_, subtract_flag_; + uint8_t sign_result_, zero_result_, bit5_result_, half_carry_flag_, bit3_result_, parity_overflow_flag_, subtract_flag_, carry_flag_; int number_of_cycles_; const MicroOp **program_table_; @@ -137,6 +150,13 @@ template class Processor: public MicroOpScheduler { #define PUSH(x) {MicroOp::Decrement16, &sp_.full}, STOREL(x.bytes.high, sp_), {MicroOp::Decrement16, &sp_.full}, STOREL(x.bytes.low, sp_) #define POP(x) FETCHL(x.bytes.low, sp_), {MicroOp::Increment16, &sp_.full}, FETCHL(x.bytes.high, sp_), {MicroOp::Increment16, &sp_.full} +#define JP(cc) Program(FETCH16(temporary_, pc_), {MicroOp::cc}, {MicroOp::Move16, &address_.full, &pc_.full}) +#define LD(a, b) Program({MicroOp::Move8, &b, &a}) + +#define LD_GROUP(r) \ + LD(r, bc_.bytes.high), LD(r, bc_.bytes.low), LD(r, de_.bytes.high), LD(r, de_.bytes.low), \ + LD(r, hl_.bytes.high), LD(r, hl_.bytes.low), Program(FETCHL(r, hl_)), LD(r, a_) + #define WAIT(n) {MicroOp::BusOperation, nullptr, nullptr, {Internal, n} } #define Program(...) { __VA_ARGS__, {MicroOp::MoveToNextProgram} } @@ -152,7 +172,7 @@ template class Processor: public MicroOpScheduler { XX, /* 0x07 RLCA */ XX, /* 0x08 EX AF, AF' */ XX, /* 0x09 ADD HL, BC */ - XX, /* 0x0a LD A, (BC) */ + Program(FETCHL(a_, bc_)), /* 0x0a LD A, (BC) */ Program(WAIT(2), {MicroOp::Decrement16, &bc_.full}), /* 0x0b DEC BC */ XX, /* 0x0c INC C */ XX, /* 0x0d DEC C */ @@ -168,7 +188,7 @@ template class Processor: public MicroOpScheduler { XX, /* 0x17 RLA */ XX, /* 0x18 JR */ XX, /* 0x19 ADD HL, DE */ - XX, /* 0x1a LD A, (DE) */ + Program(FETCHL(a_, de_)), /* 0x1a LD A, (DE) */ Program(WAIT(2), {MicroOp::Decrement16, &de_.full}), /* 0x1b DEC DE */ XX, /* 0x1c INC E */ XX, /* 0x1d DEC E */ @@ -206,39 +226,32 @@ template class Processor: public MicroOpScheduler { XX, /* 0x3d DEC A */ XX, /* 0x3e LD A, n */ XX, /* 0x3f CCF */ - XX, XX, XX, XX, XX, XX, XX, XX, // 0x40 - XX, /* 0x48 LD C, B */ - XX, /* 0x49 LD C, C */ - XX, /* 0x4a LD C, D */ - XX, /* 0x4b LD C, E */ - XX, /* 0x4c LD C, H */ - XX, /* 0x4d LD C, L */ - Program(FETCHL(bc_.bytes.low, hl_)), /* 0x4e LD C,(HL) */ - XX, /* 0x4f LD C, A */ - XX, XX, XX, XX, XX, XX, XX, XX, // 0x50 - XX, XX, XX, XX, XX, XX, XX, XX, // 0x58 - XX, XX, XX, XX, XX, XX, XX, XX, // 0x60 - XX, XX, XX, XX, XX, XX, XX, XX, // 0x68 + LD_GROUP(bc_.bytes.high), /* 0x40 LD B, B; 0x41 LD B, C; 0x42 LD B, D; 0x43 LD B, E; 0x44 LD B, H; 0x45 LD B, L; 0x46 LD B, (HL); 0x47 LD B, A */ + LD_GROUP(bc_.bytes.low), /* 0x48 LD C, B; 0x49 LD C, C; 0x4a LD C, D; 0x4b LD C, E; 0x4c LD C, H; 0x4d LD C, L; 0x4e LD C, (HL); 0x4f LD C, A */ + LD_GROUP(de_.bytes.high), /* 0x50 LD D, B; 0x51 LD D, C; 0x52 LD D, D; 0x53 LD D, E; 0x54 LD D, H; 0x55 LD D, L; 0x56 LD D, (HL); 0x57 LD D, A */ + LD_GROUP(de_.bytes.low), /* 0x58 LD E, B; 0x59 LD E, C; 0x5a LD E, D; 0x5b LD E, E; 0x5c LD E, H; 0x5d LD E, L; 0x5e LD E, (HL); 0x5f LD E, A */ + LD_GROUP(hl_.bytes.high), /* 0x60 LD H, B; 0x61 LD H, C; 0x62 LD H, D; 0x63 LD H, E; 0x64 LD H, H; 0x65 LD H, L; 0x66 LD H, (HL); 0x67 LD H, A */ + LD_GROUP(hl_.bytes.low), /* 0x68 LD L, B; 0x69 LD L, C; 0x6a LD L, D; 0x6b LD L, E; 0x6c LD L, H; 0x6d LD H, L; 0x6e LD L, (HL); 0x6f LD L, A */ XX, XX, XX, XX, XX, XX, XX, XX, // 0x70 - XX, /* 0x78 LD A, B */ - XX, /* 0x79 LD A, C */ - XX, /* 0x7a LD A, D */ - XX, /* 0x7b LD A, E */ - XX, /* 0x7c LD A, H */ - XX, /* 0x7d LD A, L */ - Program(FETCHL(a_, hl_)), /* 0x7e LD A, (HL) */ - XX, /* 0x7f LD A, A */ + LD_GROUP(a_), /* 0x78 LD A, B; 0x79 LD A, C; 0x7a LD A, D; 0x7b LD A, E; 0x7c LD A, H; 0x7d LD A, L; 0x7e LD A, (HL); 0x7f LD A, A */ XX, XX, XX, XX, XX, XX, XX, XX, // 0x80 XX, XX, XX, XX, XX, XX, XX, XX, // 0x88 XX, XX, XX, XX, XX, XX, XX, XX, // 0x90 XX, XX, XX, XX, XX, XX, XX, XX, // 0x98 XX, XX, XX, XX, XX, XX, XX, XX, // 0xa0 XX, XX, XX, XX, XX, XX, XX, XX, // 0xa8 - XX, XX, XX, XX, XX, XX, XX, XX, // 0xb0 + Program({MicroOp::Or, &hl_.bytes.high}), /* 0xb0 OR B */ + Program({MicroOp::Or, &bc_.bytes.low}), /* 0xb1 OR C */ + Program({MicroOp::Or, &hl_.bytes.high}), /* 0xb2 OR D */ + Program({MicroOp::Or, &de_.bytes.low}), /* 0xb3 OR E */ + Program({MicroOp::Or, &hl_.bytes.high}), /* 0xb4 OR H */ + Program({MicroOp::Or, &hl_.bytes.low}), /* 0xb5 OR L */ + Program(FETCHL(temporary_.bytes.low, hl_), {MicroOp::Or, &temporary_.bytes.low}), /* 0xb6 OR (HL) */ + Program({MicroOp::Or, &a_}), /* 0xb7 OR A */ XX, XX, XX, XX, XX, XX, XX, XX, // 0xb8 XX, /* 0xc0 RET NZ */ Program(POP(bc_)), /* 0xc1 POP BC */ - XX, /* 0xc2 JP NZ */ + JP(TestNZ), /* 0xc2 JP NZ */ Program(FETCH16L(address_, pc_), {MicroOp::Move16, &address_.full, &pc_.full}), /* 0xc3 JP nn */ XX, /* 0xc4 CALL NZ */ Program(WAIT(1), PUSH(bc_)), /* 0xc5 PUSH BC */ @@ -246,7 +259,7 @@ template class Processor: public MicroOpScheduler { XX, /* 0xc7 RST 00h */ XX, /* 0xc8 RET Z */ Program(POP(pc_)), /* 0xc9 RET */ - XX, /* 0xca JP Z */ + JP(TestZ), /* 0xca JP Z */ XX, /* 0xcb [CB page] */ XX, /* 0xcc CALL Z */ Program(FETCH16(address_, pc_), WAIT(1), PUSH(pc_), {MicroOp::Move16, &address_.full, &pc_.full}), /* 0xcd CALL */ @@ -254,25 +267,39 @@ template class Processor: public MicroOpScheduler { XX, /* 0xcf RST 08h */ XX, /* 0xd0 RET NC */ Program(POP(de_)), /* 0xd1 POP DE */ - XX, /* 0xd2 JP NC */ + JP(TestNC), /* 0xd2 JP NC */ XX, /* 0xd3 OUT (n), A */ XX, /* 0xd4 CALL NC */ Program(WAIT(1), PUSH(de_)), /* 0xd5 PUSH DE */ XX, /* 0xd6 SUB n */ XX, /* 0xd7 RST 10h */ - XX, XX, XX, XX, XX, XX, XX, XX, // 0xd8 + XX, /* 0xd8 RET C */ + XX, /* 0xd9 EXX */ + JP(TestC), /* 0xda JP C */ + XX, /* 0xdb IN A, (n) */ + XX, /* 0xdc CALL C */ + XX, /* 0xdd [DD page] */ + XX, /* 0xde SBC A, n */ + XX, /* 0xdf RST 18h */ XX, /* 0xe0 RET PO */ Program(POP(hl_)), /* 0xe1 POP HL */ - XX, /* 0xe2 JP PO */ + JP(TestPO), /* 0xe2 JP PO */ XX, /* 0xe3 EX (SP), HL */ XX, /* 0xe4 CALL PO */ Program(WAIT(1), PUSH(hl_)), /* 0xe5 PUSH HL */ XX, /* 0xe6 AND n */ XX, /* 0xe7 RST 20h */ - XX, XX, XX, XX, XX, XX, XX, XX, // 0xe8 + XX, /* 0xe8 RET PE */ + XX, /* 0xe9 JP (HL) */ + JP(TestPE), /* 0xea JP PE */ + XX, /* 0xeb EX DE, HL */ + XX, /* 0xec CALL PE */ + XX, /* 0xed [ED page] */ + XX, /* 0xee XOR n */ + XX, /* 0xef RST 28h */ XX, /* 0xf0 RET p */ Program(POP(temporary_), {MicroOp::DisassembleAF}), /* 0xf1 POP AF */ - XX, /* 0xf2 JP P */ + JP(TestP), /* 0xf2 JP P */ XX, /* 0xf3 DI */ XX, /* 0xf4 CALL P */ Program(WAIT(1), {MicroOp::AssembleAF}, PUSH(temporary_)), /* 0xf5 PUSH AF */ @@ -280,7 +307,7 @@ template class Processor: public MicroOpScheduler { XX, /* 0xf7 RST 30h */ XX, /* 0xf8 RET M */ Program(WAIT(2), {MicroOp::Move16, &hl_.full, &sp_.full}), /* 0xf9 LD SP, HL */ - XX, /* 0xfa JP M */ + JP(TestM), /* 0xfa JP M */ XX, /* 0xfb EI */ XX, /* 0xfc CALL M */ XX, /* 0xfd [FD page] */ @@ -357,6 +384,45 @@ template class Processor: public MicroOpScheduler { set_flags(temporary_.bytes.low); break; +#define set_parity(v) \ + parity_overflow_flag_ = v^1;\ + parity_overflow_flag_ ^= parity_overflow_flag_ >> 4;\ + parity_overflow_flag_ ^= parity_overflow_flag_ << 2;\ + parity_overflow_flag_ ^= parity_overflow_flag_ >> 1;\ + parity_overflow_flag_ &= Flag::Parity; + + case MicroOp::And: + a_ &= *(uint8_t *)operation->source; + sign_result_ = zero_result_ = bit5_result_ = bit3_result_ = a_; + parity_overflow_flag_ = 0; + set_parity(a_); + break; + + case MicroOp::Or: + a_ |= *(uint8_t *)operation->source; + sign_result_ = zero_result_ = bit5_result_ = bit3_result_ = a_; + parity_overflow_flag_ = 0; + set_parity(a_); + break; + + case MicroOp::Xor: + a_ ^= *(uint8_t *)operation->source; + sign_result_ = zero_result_ = bit5_result_ = bit3_result_ = a_; + parity_overflow_flag_ = 0; + set_parity(a_); + break; + +#undef set_parity + + case MicroOp::TestNZ: if(!zero_result_) { move_to_next_program(); checkSchedule(); } break; + case MicroOp::TestZ: if(zero_result_) { move_to_next_program(); checkSchedule(); } break; + case MicroOp::TestNC: if(carry_flag_) { move_to_next_program(); checkSchedule(); } break; + case MicroOp::TestC: if(!carry_flag_) { move_to_next_program(); checkSchedule(); } break; + case MicroOp::TestPO: if(parity_overflow_flag_) { move_to_next_program(); checkSchedule(); } break; + case MicroOp::TestPE: if(!parity_overflow_flag_) { move_to_next_program(); checkSchedule(); } break; + case MicroOp::TestP: if(sign_result_ & 0x80) { move_to_next_program(); checkSchedule(); } break; + case MicroOp::TestM: if(!(sign_result_ & 0x80)) { move_to_next_program(); checkSchedule(); } break; + default: printf("Unhandled Z80 operation %d\n", operation->type); return; @@ -384,13 +450,14 @@ template class Processor: public MicroOpScheduler { */ uint8_t get_flags() { return - carry_flag_ | (sign_result_ & Flag::Sign) | + (zero_result_ ? 0 : Flag::Zero) | (bit5_result_ & Flag::Bit5) | half_carry_flag_ | (bit3_result_ & Flag::Bit3) | parity_overflow_flag_ | - subtract_flag_; + subtract_flag_ | + carry_flag_; } /*! @@ -401,13 +468,14 @@ template class Processor: public MicroOpScheduler { @param flags The new value of the flags register. */ void set_flags(uint8_t flags) { - carry_flag_ = flags & Flag::Carry; sign_result_ = flags; + zero_result_ = (flags & Flag::Zero) ^ Flag::Zero; bit5_result_ = flags; half_carry_flag_ = flags & Flag::HalfCarry; bit3_result_ = flags; parity_overflow_flag_ = flags & Flag::Parity; subtract_flag_ = flags & Flag::Subtract; + carry_flag_ = flags & Flag::Carry; } /*! diff --git a/Processors/Z80/Z80AllRAM.cpp b/Processors/Z80/Z80AllRAM.cpp index a17299edb..d14e6a9b4 100644 --- a/Processors/Z80/Z80AllRAM.cpp +++ b/Processors/Z80/Z80AllRAM.cpp @@ -16,9 +16,10 @@ AllRAMProcessor::AllRAMProcessor() : ::CPU::AllRAMProcessor(65536) {} int AllRAMProcessor::perform_machine_cycle(const MachineCycle *cycle) { switch(cycle->operation) { case BusOperation::ReadOpcode: + printf("! "); check_address_for_trap(*cycle->address); case BusOperation::Read: - printf("r %04x\n", *cycle->address); + printf("r %04x [%02x]\n", *cycle->address, memory_[*cycle->address]); *cycle->value = memory_[*cycle->address]; break; case BusOperation::Write: