mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-17 10:30:31 +00:00
Merge pull request #130 from TomHarte/Bits35
Corrects bit 3 & 5 emulation for everything except BIT n, (HL)
This commit is contained in:
commit
18faebc93c
@ -121,7 +121,7 @@ fileprivate struct RegisterState {
|
||||
extension RegisterState: Equatable {}
|
||||
|
||||
fileprivate func ==(lhs: RegisterState, rhs: RegisterState) -> Bool {
|
||||
return (lhs.af & ~0x0028) == (rhs.af & ~0x0028) &&
|
||||
return lhs.af == rhs.af &&
|
||||
lhs.bc == rhs.bc &&
|
||||
lhs.de == rhs.de &&
|
||||
lhs.hl == rhs.hl &&
|
||||
|
@ -51,7 +51,7 @@ class ZexallTests: XCTestCase, CSTestMachineTrapHandler {
|
||||
machine.runForNumber(ofCycles: cyclesPerIteration)
|
||||
cyclesToDate += TimeInterval(cyclesPerIteration)
|
||||
if printDate.timeIntervalSinceNow < -5.0 {
|
||||
print("\(cyclesToDate / -startDate.timeIntervalSinceNow) Mhz")
|
||||
// print("\(cyclesToDate / -startDate.timeIntervalSinceNow) Mhz")
|
||||
printDate = Date()
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ template <class T> class Processor {
|
||||
bool bus_request_line_;
|
||||
|
||||
uint8_t operation_;
|
||||
RegisterPair temp16_;
|
||||
RegisterPair temp16_, memptr_;
|
||||
uint8_t temp8_;
|
||||
|
||||
struct MicroOp {
|
||||
@ -213,9 +213,10 @@ template <class T> class Processor {
|
||||
std::vector<MicroOp> all_operations;
|
||||
std::vector<MicroOp> fetch_decode_execute;
|
||||
MicroOp *fetch_decode_execute_data;
|
||||
uint8_t r_step_;
|
||||
uint8_t r_step;
|
||||
bool is_indexed;
|
||||
|
||||
InstructionPage() : r_step_(1) {}
|
||||
InstructionPage() : r_step(1), is_indexed(false) {}
|
||||
};
|
||||
std::vector<MicroOp> reset_program_;
|
||||
std::vector<MicroOp> irq_program_[3];
|
||||
@ -235,7 +236,7 @@ template <class T> class Processor {
|
||||
|
||||
#define INDEX() {MicroOp::IndexedPlaceHolder}, FETCH(temp8_, pc_), WAIT(5), {MicroOp::CalculateIndexAddress, &index}
|
||||
#define FINDEX() {MicroOp::IndexedPlaceHolder}, FETCH(temp8_, pc_), {MicroOp::CalculateIndexAddress, &index}
|
||||
#define INDEX_ADDR() (add_offsets ? temp16_ : index)
|
||||
#define INDEX_ADDR() (add_offsets ? memptr_ : index)
|
||||
|
||||
#define INC16(r) {(&r == &pc_) ? MicroOp::IncrementPC : MicroOp::Increment16, &r.full}
|
||||
|
||||
@ -268,9 +269,9 @@ template <class T> class Processor {
|
||||
|
||||
#define JP(cc) Program(FETCH16(temp16_, pc_), {MicroOp::cc}, {MicroOp::Move16, &temp16_.full, &pc_.full})
|
||||
#define CALL(cc) Program(FETCH16(temp16_, pc_), {MicroOp::cc}, WAIT(1), PUSH(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full})
|
||||
#define RET(cc) Program(WAIT(1), {MicroOp::cc}, POP(pc_))
|
||||
#define JR(cc) Program(FETCH(temp8_, pc_), {MicroOp::cc}, WAIT(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &temp16_.full, &pc_.full})
|
||||
#define RST() Program(WAIT(1), {MicroOp::CalculateRSTDestination}, PUSH(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full})
|
||||
#define RET(cc) Program(WAIT(1), {MicroOp::cc}, POP(memptr_), {MicroOp::Move16, &memptr_.full, &pc_.full})
|
||||
#define JR(cc) Program(FETCH(temp8_, pc_), {MicroOp::cc}, WAIT(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full})
|
||||
#define RST() Program(WAIT(1), {MicroOp::CalculateRSTDestination}, PUSH(pc_), {MicroOp::Move16, &memptr_.full, &pc_.full})
|
||||
#define LD(a, b) Program({MicroOp::Move8, &b, &a})
|
||||
|
||||
#define LD_GROUP(r, ri) \
|
||||
@ -485,30 +486,30 @@ template <class T> class Processor {
|
||||
|
||||
InstructionTable base_program_table = {
|
||||
/* 0x00 NOP */ NOP, /* 0x01 LD BC, nn */ Program(FETCH16(bc_, pc_)),
|
||||
/* 0x02 LD (BC), A */ Program(STOREL(a_, bc_)),
|
||||
/* 0x02 LD (BC), A */ Program({MicroOp::Move16, &bc_.full, &memptr_.full}, STORE(a_, memptr_)),
|
||||
|
||||
/* 0x03 INC BC; 0x04 INC B; 0x05 DEC B; 0x06 LD B, n */
|
||||
INC_INC_DEC_LD(bc_, bc_.bytes.high),
|
||||
|
||||
/* 0x07 RLCA */ Program({MicroOp::RLCA}),
|
||||
/* 0x08 EX AF, AF' */ Program({MicroOp::ExAFAFDash}), /* 0x09 ADD HL, BC */ ADD16(index, bc_),
|
||||
/* 0x0a LD A, (BC) */ Program(FETCHL(a_, bc_)),
|
||||
/* 0x0a LD A, (BC) */ Program({MicroOp::Move16, &bc_.full, &memptr_.full}, FETCH(a_, memptr_)),
|
||||
|
||||
/* 0x0b DEC BC; 0x0c INC C; 0x0d DEC C; 0x0e LD C, n */
|
||||
DEC_INC_DEC_LD(bc_, bc_.bytes.low),
|
||||
|
||||
/* 0x0f RRCA */ Program({MicroOp::RRCA}),
|
||||
/* 0x10 DJNZ */ Program(WAIT(1), FETCH(temp8_, pc_), {MicroOp::DJNZ}, WAIT(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &temp16_.full, &pc_.full}),
|
||||
/* 0x10 DJNZ */ Program(WAIT(1), FETCH(temp8_, pc_), {MicroOp::DJNZ}, WAIT(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}),
|
||||
/* 0x11 LD DE, nn */ Program(FETCH16(de_, pc_)),
|
||||
/* 0x12 LD (DE), A */ Program(STOREL(a_, de_)),
|
||||
/* 0x12 LD (DE), A */ Program({MicroOp::Move16, &de_.full, &memptr_.full}, STORE(a_, memptr_)),
|
||||
|
||||
/* 0x13 INC DE; 0x14 INC D; 0x15 DEC D; 0x16 LD D, n */
|
||||
INC_INC_DEC_LD(de_, de_.bytes.high),
|
||||
|
||||
/* 0x17 RLA */ Program({MicroOp::RLA}),
|
||||
/* 0x18 JR */ Program(FETCH(temp8_, pc_), WAIT(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &temp16_.full, &pc_.full}),
|
||||
/* 0x18 JR */ Program(FETCH(temp8_, pc_), WAIT(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}),
|
||||
/* 0x19 ADD HL, DE */ ADD16(index, de_),
|
||||
/* 0x1a LD A, (DE) */ Program(FETCHL(a_, de_)),
|
||||
/* 0x1a LD A, (DE) */ Program({MicroOp::Move16, &de_.full, &memptr_.full}, FETCH(a_, memptr_)),
|
||||
|
||||
/* 0x1b DEC DE; 0x1c INC E; 0x1d DEC E; 0x1e LD E, n */
|
||||
DEC_INC_DEC_LD(de_, de_.bytes.low),
|
||||
@ -537,7 +538,7 @@ template <class T> class Processor {
|
||||
/* 0x37 SCF */ Program({MicroOp::SCF}),
|
||||
/* 0x38 JR C */ JR(TestC),
|
||||
/* 0x39 ADD HL, SP */ ADD16(index, sp_),
|
||||
/* 0x3a LD A, (nn) */ Program(FETCH16(temp16_, pc_), FETCHL(a_, temp16_)),
|
||||
/* 0x3a LD A, (nn) */ Program(FETCH16(memptr_, pc_), FETCH(a_, memptr_)),
|
||||
/* 0x3b DEC SP */ Program(WAIT(2), {MicroOp::Decrement16, &sp_.full}),
|
||||
|
||||
/* 0x3c INC A; 0x3d DEC A; 0x3e LD A, n */
|
||||
@ -620,7 +621,7 @@ template <class T> class Processor {
|
||||
/* 0xde SBC A, n */ Program(FETCH(temp8_, pc_), {MicroOp::SBC8, &temp8_}),
|
||||
/* 0xdf RST 18h */ RST(),
|
||||
/* 0xe0 RET PO */ RET(TestPO), /* 0xe1 POP HL */ Program(POP(index)),
|
||||
/* 0xe2 JP PO */ JP(TestPO), /* 0xe3 EX (SP), HL */Program(POP(temp16_), WAIT(1), PUSH(index), WAIT(2), {MicroOp::Move16, &temp16_.full, &index.full}),
|
||||
/* 0xe2 JP PO */ JP(TestPO), /* 0xe3 EX (SP), HL */Program(POP(memptr_), WAIT(1), PUSH(index), WAIT(2), {MicroOp::Move16, &memptr_.full, &index.full}),
|
||||
/* 0xe4 CALL PO */ CALL(TestPO), /* 0xe5 PUSH HL */ Program(WAIT(1), PUSH(index)),
|
||||
/* 0xe6 AND n */ Program(FETCH(temp8_, pc_), {MicroOp::And, &temp8_}),
|
||||
/* 0xe7 RST 20h */ RST(),
|
||||
@ -682,8 +683,13 @@ template <class T> class Processor {
|
||||
assemble_base_page(fd_page_, iy_, true, fdcb_page_);
|
||||
assemble_ed_page(ed_page_);
|
||||
|
||||
fdcb_page_.r_step_ = 0;
|
||||
ddcb_page_.r_step_ = 0;
|
||||
fdcb_page_.r_step = 0;
|
||||
fd_page_.is_indexed = true;
|
||||
fdcb_page_.is_indexed = true;
|
||||
|
||||
ddcb_page_.r_step = 0;
|
||||
dd_page_.is_indexed = true;
|
||||
ddcb_page_.is_indexed = true;
|
||||
|
||||
assemble_fetch_decode_execute(base_page_, 4);
|
||||
assemble_fetch_decode_execute(dd_page_, 4);
|
||||
@ -793,7 +799,7 @@ template <class T> class Processor {
|
||||
advance_operation();
|
||||
break;
|
||||
case MicroOp::DecodeOperation:
|
||||
r_ = (r_ & 0x80) | ((r_ + current_instruction_page_->r_step_) & 0x7f);
|
||||
r_ = (r_ & 0x80) | ((r_ + current_instruction_page_->r_step) & 0x7f);
|
||||
pc_.full += pc_increment_;
|
||||
case MicroOp::DecodeOperationNoRChange:
|
||||
scheduled_program_counter_ = current_instruction_page_->instructions[operation_ & halt_mask_];
|
||||
@ -871,7 +877,7 @@ template <class T> class Processor {
|
||||
break;
|
||||
|
||||
case MicroOp::CalculateRSTDestination:
|
||||
temp16_.full = operation_ & 0x38;
|
||||
memptr_.full = operation_ & 0x38;
|
||||
break;
|
||||
|
||||
#pragma mark - 8-bit arithmetic
|
||||
@ -1058,7 +1064,8 @@ template <class T> class Processor {
|
||||
#pragma mark - 16-bit arithmetic
|
||||
|
||||
case MicroOp::ADD16: {
|
||||
uint16_t sourceValue = *(uint16_t *)operation->source;
|
||||
memptr_.full = *(uint16_t *)operation->source;
|
||||
uint16_t sourceValue = memptr_.full;
|
||||
uint16_t destinationValue = *(uint16_t *)operation->destination;
|
||||
int result = sourceValue + destinationValue;
|
||||
int halfResult = (sourceValue&0xfff) + (destinationValue&0xfff);
|
||||
@ -1072,7 +1079,8 @@ template <class T> class Processor {
|
||||
} break;
|
||||
|
||||
case MicroOp::ADC16: {
|
||||
uint16_t sourceValue = *(uint16_t *)operation->source;
|
||||
memptr_.full = *(uint16_t *)operation->source;
|
||||
uint16_t sourceValue = memptr_.full;
|
||||
uint16_t destinationValue = *(uint16_t *)operation->destination;
|
||||
int result = sourceValue + destinationValue + (carry_result_ & Flag::Carry);
|
||||
int halfResult = (sourceValue&0xfff) + (destinationValue&0xfff) + (carry_result_ & Flag::Carry);
|
||||
@ -1091,7 +1099,8 @@ template <class T> class Processor {
|
||||
} break;
|
||||
|
||||
case MicroOp::SBC16: {
|
||||
uint16_t sourceValue = *(uint16_t *)operation->source;
|
||||
memptr_.full = *(uint16_t *)operation->source;
|
||||
uint16_t sourceValue = memptr_.full;
|
||||
uint16_t destinationValue = *(uint16_t *)operation->destination;
|
||||
int result = destinationValue - sourceValue - (carry_result_ & Flag::Carry);
|
||||
int halfResult = (destinationValue&0xfff) - (sourceValue&0xfff) - (carry_result_ & Flag::Carry);
|
||||
@ -1163,7 +1172,8 @@ template <class T> class Processor {
|
||||
bc_.full--; \
|
||||
de_.full += dir; \
|
||||
hl_.full += dir; \
|
||||
bit53_result_ = a_ + temp8_; \
|
||||
uint8_t sum = a_ + temp8_; \
|
||||
bit53_result_ = (sum&0x8) | ((sum & 0x02) << 4); \
|
||||
subtract_flag_ = 0; \
|
||||
half_carry_result_ = 0; \
|
||||
parity_overflow_result_ = bc_.full ? Flag::Parity : 0;
|
||||
@ -1198,8 +1208,10 @@ template <class T> class Processor {
|
||||
parity_overflow_result_ = bc_.full ? Flag::Parity : 0; \
|
||||
half_carry_result_ = halfResult; \
|
||||
subtract_flag_ = Flag::Subtract; \
|
||||
sign_result_ = zero_result_ = result; \
|
||||
\
|
||||
result -= (halfResult >> 4)&1; \
|
||||
bit53_result_ = (uint8_t)((result&0x8) | ((result&0x2) << 4)); \
|
||||
sign_result_ = zero_result_ = result;
|
||||
|
||||
case MicroOp::CPDR: {
|
||||
CPxR_STEP(-1);
|
||||
@ -1212,10 +1224,12 @@ template <class T> class Processor {
|
||||
} break;
|
||||
|
||||
case MicroOp::CPD: {
|
||||
memptr_.full--;
|
||||
CPxR_STEP(-1);
|
||||
} break;
|
||||
|
||||
case MicroOp::CPI: {
|
||||
memptr_.full++;
|
||||
CPxR_STEP(1);
|
||||
} break;
|
||||
|
||||
@ -1253,10 +1267,12 @@ template <class T> class Processor {
|
||||
} break;
|
||||
|
||||
case MicroOp::IND: {
|
||||
memptr_.full = bc_.full - 1;
|
||||
INxR_STEP(-1);
|
||||
} break;
|
||||
|
||||
case MicroOp::INI: {
|
||||
memptr_.full = bc_.full + 1;
|
||||
INxR_STEP(1);
|
||||
} break;
|
||||
|
||||
@ -1286,10 +1302,12 @@ template <class T> class Processor {
|
||||
|
||||
case MicroOp::OUTD: {
|
||||
OUTxR_STEP(-1);
|
||||
memptr_.full = bc_.full - 1;
|
||||
} break;
|
||||
|
||||
case MicroOp::OUTI: {
|
||||
OUTxR_STEP(1);
|
||||
memptr_.full = bc_.full + 1;
|
||||
} break;
|
||||
|
||||
#undef OUTxR_STEP
|
||||
@ -1299,8 +1317,13 @@ template <class T> class Processor {
|
||||
case MicroOp::BIT: {
|
||||
uint8_t result = *(uint8_t *)operation->source & (1 << ((operation_ >> 3)&7));
|
||||
|
||||
if(current_instruction_page_->is_indexed || ((operation_&0x08) == 7)) {
|
||||
bit53_result_ = memptr_.bytes.high;
|
||||
} else {
|
||||
bit53_result_ = *(uint8_t *)operation->source;
|
||||
}
|
||||
|
||||
sign_result_ = zero_result_ = result;
|
||||
bit53_result_ = *(uint8_t *)operation->source; // This is a divergence between FUSE and The Undocumented Z80 Documented.
|
||||
half_carry_result_ = Flag::HalfCarry;
|
||||
subtract_flag_ = 0;
|
||||
parity_overflow_result_ = result ? 0 : Flag::Parity;
|
||||
@ -1412,6 +1435,7 @@ template <class T> class Processor {
|
||||
bit53_result_ = zero_result_ = sign_result_ = a_;
|
||||
|
||||
case MicroOp::RRD: {
|
||||
memptr_.full = hl_.full + 1;
|
||||
uint8_t low_nibble = a_ & 0xf;
|
||||
a_ = (a_ & 0xf0) | (temp8_ & 0xf);
|
||||
temp8_ = (temp8_ >> 4) | (low_nibble << 4);
|
||||
@ -1419,6 +1443,7 @@ template <class T> class Processor {
|
||||
} break;
|
||||
|
||||
case MicroOp::RLD: {
|
||||
memptr_.full = hl_.full + 1;
|
||||
uint8_t low_nibble = a_ & 0xf;
|
||||
a_ = (a_ & 0xf0) | (temp8_ >> 4);
|
||||
temp8_ = (temp8_ << 4) | low_nibble;
|
||||
@ -1516,7 +1541,7 @@ template <class T> class Processor {
|
||||
break;
|
||||
|
||||
case MicroOp::CalculateIndexAddress:
|
||||
temp16_.full = *(uint16_t *)operation->source + (int8_t)temp8_;
|
||||
memptr_.full = *(uint16_t *)operation->source + (int8_t)temp8_;
|
||||
break;
|
||||
|
||||
case MicroOp::IndexedPlaceHolder:
|
||||
|
Loading…
x
Reference in New Issue
Block a user