1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-23 03:32:32 +00:00

Merge pull request #366 from TomHarte/MoreMemptr

Improves Z80 memptr behaviour.
This commit is contained in:
Thomas Harte 2018-03-09 10:05:57 -05:00 committed by GitHub
commit 53f05efb2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 209 additions and 113 deletions

View File

@ -23,6 +23,16 @@ class Z80MemptrTests: XCTestCase {
return machine.value(for: .memPtr)
}
fileprivate func insert16(program: inout [UInt8], address: Int, offset: size_t) {
program[offset] = UInt8(address & 0x00ff)
program[offset + 1] = UInt8(address >> 8)
}
/*
Re: comments below:
All the CPU chips tested give the same results except KP1858BM1 and T34BM1 slices noted as "BM1".
*/
// LD A, (addr)
func testLDAnn() {
// MEMPTR = addr+1
@ -39,11 +49,40 @@ class Z80MemptrTests: XCTestCase {
}
}
/* TODO:
LD (addr),A
MEMPTR_low = (addr + 1) & #FF, MEMPTR_hi = A
Note for *BM1: MEMPTR_low = (addr + 1) & #FF, MEMPTR_hi = 0
*/
// LD (bc/de),A, and LD (nn),A
func testLDrpA() {
// MEMPTR_low = (addr + 1) & #FF, MEMPTR_hi = A
// Note for *BM1: MEMPTR_low = (addr + 1) & #FF, MEMPTR_hi = 0
let bcProgram: [UInt8] = [
0x02
]
let deProgram: [UInt8] = [
0x12
]
var nnProgram: [UInt8] = [
0x32, 0x00, 0x00
]
for addr in 0 ..< 256 {
machine.setValue(UInt16(addr), for: .BC)
machine.setValue(UInt16(addr), for: .DE)
insert16(program: &nnProgram, address: addr, offset: 1)
for a in 0 ..< 256 {
machine.setValue(UInt16(a), for: .A)
let expectedResult = UInt16(((addr + 1) & 0xff) + (a << 8))
let bcResult = test(program: bcProgram, length: 7, initialValue: 0xffff)
let deResult = test(program: deProgram, length: 7, initialValue: 0xffff)
let nnResult = test(program: nnProgram, length: 13, initialValue: 0xffff)
XCTAssertEqual(bcResult, expectedResult)
XCTAssertEqual(deResult, expectedResult)
XCTAssertEqual(nnResult, expectedResult)
}
}
}
// LD A, (rp)
func testLDArp() {
@ -68,19 +107,44 @@ class Z80MemptrTests: XCTestCase {
}
}
/* TODO:
LD (rp),A where rp -- BC or DE
MEMPTR_low = (rp + 1) & #FF, MEMPTR_hi = A
Note for *BM1: MEMPTR_low = (rp + 1) & #FF, MEMPTR_hi = 0
*/
// LD (addr), rp
func testLDnnrp() {
// MEMPTR = addr + 1
var ldnnhlBaseProgram: [UInt8] = [
0x22, 0x00, 0x00
]
var ldnnbcEDProgram: [UInt8] = [
0xed, 0x43, 0x00, 0x00
]
var ldnndeEDProgram: [UInt8] = [
0xed, 0x53, 0x00, 0x00
]
var ldnnhlEDProgram: [UInt8] = [
0xed, 0x63, 0x00, 0x00
]
var ldnnspEDProgram: [UInt8] = [
0xed, 0x73, 0x00, 0x00
]
/* TODO:
LD (addr), rp
MEMPTR = addr + 1
*/
for addr in 0 ..< 65536 {
insert16(program: &ldnnhlBaseProgram, address: addr, offset: 1)
insert16(program: &ldnnbcEDProgram, address: addr, offset: 2)
insert16(program: &ldnndeEDProgram, address: addr, offset: 2)
insert16(program: &ldnnhlEDProgram, address: addr, offset: 2)
insert16(program: &ldnnspEDProgram, address: addr, offset: 2)
let expectedResult = UInt16((addr + 1) & 0xffff)
XCTAssertEqual(test(program: ldnnhlBaseProgram, length: 16, initialValue: expectedResult ^ 1), expectedResult)
XCTAssertEqual(test(program: ldnnbcEDProgram, length: 20, initialValue: expectedResult ^ 1), expectedResult)
XCTAssertEqual(test(program: ldnndeEDProgram, length: 20, initialValue: expectedResult ^ 1), expectedResult)
XCTAssertEqual(test(program: ldnnhlEDProgram, length: 20, initialValue: expectedResult ^ 1), expectedResult)
XCTAssertEqual(test(program: ldnnspEDProgram, length: 20, initialValue: expectedResult ^ 1), expectedResult)
}
}
// LD rp, (addr)
func testLDnnrp() {
func testLDrpnn() {
// MEMPTR = addr+1
var hlBaseProgram: [UInt8] = [
0x22, 0x00, 0x00

View File

@ -54,9 +54,12 @@ template < class T,
}
while(true) {
const MicroOp *operation = scheduled_program_counter_;
const MicroOp *const operation = scheduled_program_counter_;
scheduled_program_counter_++;
#define set_did_compute_flags() \
flag_adjustment_history_ |= 1;
#define set_parity(v) \
parity_overflow_result_ = static_cast<uint8_t>(v^1);\
parity_overflow_result_ ^= parity_overflow_result_ >> 4;\
@ -90,6 +93,7 @@ template < class T,
ir_.bytes.low = (ir_.bytes.low & 0x80) | ((ir_.bytes.low + current_instruction_page_->r_step) & 0x7f);
pc_.full += pc_increment_ & static_cast<uint16_t>(halt_mask_);
scheduled_program_counter_ = current_instruction_page_->instructions[operation_ & halt_mask_];
flag_adjustment_history_ <<= 1;
break;
case MicroOp::DecodeOperationNoRChange:
refresh_addr_ = ir_;
@ -110,6 +114,7 @@ template < class T,
case MicroOp::DisassembleAF:
a_ = temp16_.bytes.high;
set_flags(temp16_.bytes.low);
//
break;
// MARK: - Logical
@ -119,7 +124,8 @@ template < class T,
set_parity(a_); \
half_carry_result_ = hf; \
subtract_flag_ = 0; \
carry_result_ = 0;
carry_result_ = 0; \
set_did_compute_flags();
case MicroOp::And:
a_ &= *static_cast<uint8_t *>(operation->source);
@ -143,20 +149,31 @@ template < class T,
subtract_flag_ = Flag::Subtract;
half_carry_result_ = Flag::HalfCarry;
bit53_result_ = a_;
set_did_compute_flags();
break;
case MicroOp::CCF:
half_carry_result_ = static_cast<uint8_t>(carry_result_ << 4);
carry_result_ ^= Flag::Carry;
subtract_flag_ = 0;
bit53_result_ = a_;
if(flag_adjustment_history_&2) {
bit53_result_ = a_;
} else {
bit53_result_ |= a_;
}
set_did_compute_flags();
break;
case MicroOp::SCF:
carry_result_ = Flag::Carry;
half_carry_result_ = 0;
subtract_flag_ = 0;
bit53_result_ = a_;
if(flag_adjustment_history_&2) {
bit53_result_ = a_;
} else {
bit53_result_ |= a_;
}
set_did_compute_flags();
break;
// MARK: - Flow control
@ -180,68 +197,69 @@ template < class T,
half_carry_result_ = static_cast<uint8_t>(half_result); \
parity_overflow_result_ = static_cast<uint8_t>(overflow >> 5); \
subtract_flag_ = sub; \
bit53_result_ = static_cast<uint8_t>(b53);
bit53_result_ = static_cast<uint8_t>(b53); \
set_did_compute_flags();
case MicroOp::CP8: {
uint8_t value = *static_cast<uint8_t *>(operation->source);
int result = a_ - value;
int half_result = (a_&0xf) - (value&0xf);
const uint8_t value = *static_cast<uint8_t *>(operation->source);
const int result = a_ - value;
const int half_result = (a_&0xf) - (value&0xf);
// overflow for a subtraction is when the signs were originally
// different and the result is different again
int overflow = (value^a_) & (result^a_);
const int overflow = (value^a_) & (result^a_);
// the 5 and 3 flags come from the operand, atypically
set_arithmetic_flags(Flag::Subtract, value);
} break;
case MicroOp::SUB8: {
uint8_t value = *static_cast<uint8_t *>(operation->source);
int result = a_ - value;
int half_result = (a_&0xf) - (value&0xf);
const uint8_t value = *static_cast<uint8_t *>(operation->source);
const int result = a_ - value;
const int half_result = (a_&0xf) - (value&0xf);
// overflow for a subtraction is when the signs were originally
// different and the result is different again
int overflow = (value^a_) & (result^a_);
const int overflow = (value^a_) & (result^a_);
a_ = static_cast<uint8_t>(result);
set_arithmetic_flags(Flag::Subtract, result);
} break;
case MicroOp::SBC8: {
uint8_t value = *static_cast<uint8_t *>(operation->source);
int result = a_ - value - (carry_result_ & Flag::Carry);
int half_result = (a_&0xf) - (value&0xf) - (carry_result_ & Flag::Carry);
const uint8_t value = *static_cast<uint8_t *>(operation->source);
const int result = a_ - value - (carry_result_ & Flag::Carry);
const int half_result = (a_&0xf) - (value&0xf) - (carry_result_ & Flag::Carry);
// overflow for a subtraction is when the signs were originally
// different and the result is different again
int overflow = (value^a_) & (result^a_);
const int overflow = (value^a_) & (result^a_);
a_ = static_cast<uint8_t>(result);
set_arithmetic_flags(Flag::Subtract, result);
} break;
case MicroOp::ADD8: {
uint8_t value = *static_cast<uint8_t *>(operation->source);
int result = a_ + value;
int half_result = (a_&0xf) + (value&0xf);
const uint8_t value = *static_cast<uint8_t *>(operation->source);
const int result = a_ + value;
const int half_result = (a_&0xf) + (value&0xf);
// overflow for addition is when the signs were originally
// the same and the result is different
int overflow = ~(value^a_) & (result^a_);
const int overflow = ~(value^a_) & (result^a_);
a_ = static_cast<uint8_t>(result);
set_arithmetic_flags(0, result);
} break;
case MicroOp::ADC8: {
uint8_t value = *static_cast<uint8_t *>(operation->source);
int result = a_ + value + (carry_result_ & Flag::Carry);
int half_result = (a_&0xf) + (value&0xf) + (carry_result_ & Flag::Carry);
const uint8_t value = *static_cast<uint8_t *>(operation->source);
const int result = a_ + value + (carry_result_ & Flag::Carry);
const int half_result = (a_&0xf) + (value&0xf) + (carry_result_ & Flag::Carry);
// overflow for addition is when the signs were originally
// the same and the result is different
int overflow = ~(value^a_) & (result^a_);
const int overflow = ~(value^a_) & (result^a_);
a_ = static_cast<uint8_t>(result);
set_arithmetic_flags(0, result);
@ -250,9 +268,9 @@ template < class T,
#undef set_arithmetic_flags
case MicroOp::NEG: {
int overflow = (a_ == 0x80);
int result = -a_;
int halfResult = -(a_&0xf);
const int overflow = (a_ == 0x80);
const int result = -a_;
const int halfResult = -(a_&0xf);
a_ = static_cast<uint8_t>(result);
bit53_result_ = sign_result_ = zero_result_ = a_;
@ -260,16 +278,17 @@ template < class T,
subtract_flag_ = Flag::Subtract;
carry_result_ = static_cast<uint8_t>(result >> 8);
half_carry_result_ = static_cast<uint8_t>(halfResult);
set_did_compute_flags();
} break;
case MicroOp::Increment8: {
uint8_t value = *static_cast<uint8_t *>(operation->source);
int result = value + 1;
const uint8_t value = *static_cast<uint8_t *>(operation->source);
const int result = value + 1;
// with an increment, overflow occurs if the sign changes from
// positive to negative
int overflow = (value ^ result) & ~value;
int half_result = (value&0xf) + 1;
const int overflow = (value ^ result) & ~value;
const int half_result = (value&0xf) + 1;
*static_cast<uint8_t *>(operation->source) = static_cast<uint8_t>(result);
@ -278,16 +297,17 @@ template < class T,
half_carry_result_ = static_cast<uint8_t>(half_result);
parity_overflow_result_ = static_cast<uint8_t>(overflow >> 5);
subtract_flag_ = 0;
set_did_compute_flags();
} break;
case MicroOp::Decrement8: {
uint8_t value = *static_cast<uint8_t *>(operation->source);
int result = value - 1;
const uint8_t value = *static_cast<uint8_t *>(operation->source);
const int result = value - 1;
// with a decrement, overflow occurs if the sign changes from
// negative to positive
int overflow = (value ^ result) & value;
int half_result = (value&0xf) - 1;
const int overflow = (value ^ result) & value;
const int half_result = (value&0xf) - 1;
*static_cast<uint8_t *>(operation->source) = static_cast<uint8_t>(result);
@ -296,28 +316,23 @@ template < class T,
half_carry_result_ = static_cast<uint8_t>(half_result);
parity_overflow_result_ = static_cast<uint8_t>(overflow >> 5);
subtract_flag_ = Flag::Subtract;
set_did_compute_flags();
} break;
case MicroOp::DAA: {
int lowNibble = a_ & 0xf;
int highNibble = a_ >> 4;
const int lowNibble = a_ & 0xf;
const int highNibble = a_ >> 4;
int amountToAdd = 0;
if(carry_result_ & Flag::Carry)
{
if(carry_result_ & Flag::Carry) {
amountToAdd = (lowNibble > 0x9 || (half_carry_result_ & Flag::HalfCarry)) ? 0x66 : 0x60;
}
else
{
if(half_carry_result_ & Flag::HalfCarry)
{
} else {
if(half_carry_result_ & Flag::HalfCarry) {
if(lowNibble > 0x9)
amountToAdd = (highNibble > 0x8) ? 0x66 : 0x06;
else
amountToAdd = (highNibble > 0x9) ? 0x66 : 0x06;
}
else
{
} else {
if(lowNibble > 0x9)
amountToAdd = (highNibble > 0x8) ? 0x66 : 0x06;
else
@ -325,25 +340,18 @@ template < class T,
}
}
if(!(carry_result_ & Flag::Carry))
{
if(lowNibble > 0x9)
{
if(!(carry_result_ & Flag::Carry)) {
if(lowNibble > 0x9) {
if(highNibble > 0x8) carry_result_ = Flag::Carry;
}
else
{
} else {
if(highNibble > 0x9) carry_result_ = Flag::Carry;
}
}
if(subtract_flag_)
{
if(subtract_flag_) {
a_ -= amountToAdd;
half_carry_result_ = ((half_carry_result_ & Flag::HalfCarry) && lowNibble < 0x6) ? Flag::HalfCarry : 0;
}
else
{
} else {
a_ += amountToAdd;
half_carry_result_ = (lowNibble > 0x9) ? Flag::HalfCarry : 0;
}
@ -351,21 +359,23 @@ template < class T,
sign_result_ = zero_result_ = bit53_result_ = a_;
set_parity(a_);
set_did_compute_flags();
} break;
// MARK: - 16-bit arithmetic
case MicroOp::ADD16: {
memptr_.full = *static_cast<uint16_t *>(operation->destination);
uint16_t sourceValue = *static_cast<uint16_t *>(operation->source);
uint16_t destinationValue = memptr_.full;
int result = sourceValue + destinationValue;
int halfResult = (sourceValue&0xfff) + (destinationValue&0xfff);
const uint16_t sourceValue = *static_cast<uint16_t *>(operation->source);
const uint16_t destinationValue = memptr_.full;
const int result = sourceValue + destinationValue;
const int halfResult = (sourceValue&0xfff) + (destinationValue&0xfff);
bit53_result_ = static_cast<uint8_t>(result >> 8);
carry_result_ = static_cast<uint8_t>(result >> 16);
half_carry_result_ = static_cast<uint8_t>(halfResult >> 8);
subtract_flag_ = 0;
set_did_compute_flags();
*static_cast<uint16_t *>(operation->destination) = static_cast<uint16_t>(result);
memptr_.full++;
@ -373,12 +383,12 @@ template < class T,
case MicroOp::ADC16: {
memptr_.full = *static_cast<uint16_t *>(operation->destination);
uint16_t sourceValue = *static_cast<uint16_t *>(operation->source);
uint16_t destinationValue = memptr_.full;
int result = sourceValue + destinationValue + (carry_result_ & Flag::Carry);
int halfResult = (sourceValue&0xfff) + (destinationValue&0xfff) + (carry_result_ & Flag::Carry);
const uint16_t sourceValue = *static_cast<uint16_t *>(operation->source);
const uint16_t destinationValue = memptr_.full;
const int result = sourceValue + destinationValue + (carry_result_ & Flag::Carry);
const int halfResult = (sourceValue&0xfff) + (destinationValue&0xfff) + (carry_result_ & Flag::Carry);
int overflow = (result ^ destinationValue) & ~(destinationValue ^ sourceValue);
const int overflow = (result ^ destinationValue) & ~(destinationValue ^ sourceValue);
bit53_result_ =
sign_result_ = static_cast<uint8_t>(result >> 8);
@ -387,6 +397,7 @@ template < class T,
carry_result_ = static_cast<uint8_t>(result >> 16);
half_carry_result_ = static_cast<uint8_t>(halfResult >> 8);
parity_overflow_result_ = static_cast<uint8_t>(overflow >> 13);
set_did_compute_flags();
*static_cast<uint16_t *>(operation->destination) = static_cast<uint16_t>(result);
memptr_.full++;
@ -394,15 +405,15 @@ template < class T,
case MicroOp::SBC16: {
memptr_.full = *static_cast<uint16_t *>(operation->destination);
uint16_t sourceValue = *static_cast<uint16_t *>(operation->source);
uint16_t destinationValue = memptr_.full;
int result = destinationValue - sourceValue - (carry_result_ & Flag::Carry);
int halfResult = (destinationValue&0xfff) - (sourceValue&0xfff) - (carry_result_ & Flag::Carry);
const uint16_t sourceValue = *static_cast<uint16_t *>(operation->source);
const uint16_t destinationValue = memptr_.full;
const int result = destinationValue - sourceValue - (carry_result_ & Flag::Carry);
const int halfResult = (destinationValue&0xfff) - (sourceValue&0xfff) - (carry_result_ & Flag::Carry);
// subtraction, so parity rules are:
// signs of operands were different,
// sign of result is different
int overflow = (result ^ destinationValue) & (sourceValue ^ destinationValue);
const int overflow = (result ^ destinationValue) & (sourceValue ^ destinationValue);
bit53_result_ =
sign_result_ = static_cast<uint8_t>(result >> 8);
@ -411,6 +422,7 @@ template < class T,
carry_result_ = static_cast<uint8_t>(result >> 16);
half_carry_result_ = static_cast<uint8_t>(halfResult >> 8);
parity_overflow_result_ = static_cast<uint8_t>(overflow >> 13);
set_did_compute_flags();
*static_cast<uint16_t *>(operation->destination) = static_cast<uint16_t>(result);
memptr_.full++;
@ -446,8 +458,8 @@ template < class T,
} break;
case MicroOp::ExAFAFDash: {
uint8_t a = a_;
uint8_t f = get_flags();
const uint8_t a = a_;
const uint8_t f = get_flags();
set_flags(afDash_.bytes.low);
a_ = afDash_.bytes.high;
afDash_.bytes.high = a;
@ -476,11 +488,12 @@ template < class T,
bc_.full--; \
de_.full += dir; \
hl_.full += dir; \
uint8_t sum = a_ + temp8_; \
const uint8_t sum = a_ + temp8_; \
bit53_result_ = static_cast<uint8_t>((sum&0x8) | ((sum & 0x02) << 4)); \
subtract_flag_ = 0; \
half_carry_result_ = 0; \
parity_overflow_result_ = bc_.full ? Flag::Parity : 0;
parity_overflow_result_ = bc_.full ? Flag::Parity : 0; \
set_did_compute_flags();
case MicroOp::LDDR: {
LDxR_STEP(-1);
@ -507,7 +520,7 @@ template < class T,
bc_.full--; \
\
uint8_t result = a_ - temp8_; \
uint8_t halfResult = (a_&0xf) - (temp8_&0xf); \
const uint8_t halfResult = (a_&0xf) - (temp8_&0xf); \
\
parity_overflow_result_ = bc_.full ? Flag::Parity : 0; \
half_carry_result_ = halfResult; \
@ -516,6 +529,7 @@ template < class T,
\
result -= (halfResult >> 4)&1; \
bit53_result_ = static_cast<uint8_t>((result&0x8) | ((result&0x2) << 4)); \
set_did_compute_flags();
case MicroOp::CPDR: {
CPxR_STEP(-1);
@ -546,7 +560,7 @@ template < class T,
sign_result_ = zero_result_ = bit53_result_ = bc_.bytes.high; \
subtract_flag_ = (temp8_ >> 6) & Flag::Subtract; \
\
int next_bc = bc_.bytes.low + dir; \
const int next_bc = bc_.bytes.low + dir; \
int summation = temp8_ + (next_bc&0xff); \
\
if(summation > 0xff) { \
@ -558,7 +572,8 @@ template < class T,
} \
\
summation = (summation&7) ^ bc_.bytes.high; \
set_parity(summation);
set_parity(summation); \
set_did_compute_flags();
case MicroOp::INDR: {
INxR_STEP(-1);
@ -598,7 +613,8 @@ template < class T,
} \
\
summation = (summation&7) ^ bc_.bytes.high; \
set_parity(summation);
set_parity(summation); \
set_did_compute_flags();
case MicroOp::OUT_R:
REPEAT(bc_.bytes.high);
@ -619,9 +635,9 @@ template < class T,
// MARK: - Bit Manipulation
case MicroOp::BIT: {
uint8_t result = *static_cast<uint8_t *>(operation->source) & (1 << ((operation_ >> 3)&7));
const uint8_t result = *static_cast<uint8_t *>(operation->source) & (1 << ((operation_ >> 3)&7));
if(current_instruction_page_->is_indexed || ((operation_&0x08) == 7)) {
if(current_instruction_page_->is_indexed || ((operation_&0x07) == 6)) {
bit53_result_ = memptr_.bytes.high;
} else {
bit53_result_ = *static_cast<uint8_t *>(operation->source);
@ -631,6 +647,7 @@ template < class T,
half_carry_result_ = Flag::HalfCarry;
subtract_flag_ = 0;
parity_overflow_result_ = result ? 0 : Flag::Parity;
set_did_compute_flags();
} break;
case MicroOp::RES:
@ -646,28 +663,29 @@ template < class T,
#define set_rotate_flags() \
bit53_result_ = a_; \
carry_result_ = new_carry; \
subtract_flag_ = half_carry_result_ = 0;
subtract_flag_ = half_carry_result_ = 0; \
set_did_compute_flags();
case MicroOp::RLA: {
uint8_t new_carry = a_ >> 7;
const uint8_t new_carry = a_ >> 7;
a_ = static_cast<uint8_t>((a_ << 1) | (carry_result_ & Flag::Carry));
set_rotate_flags();
} break;
case MicroOp::RRA: {
uint8_t new_carry = a_ & 1;
const uint8_t new_carry = a_ & 1;
a_ = static_cast<uint8_t>((a_ >> 1) | (carry_result_ << 7));
set_rotate_flags();
} break;
case MicroOp::RLCA: {
uint8_t new_carry = a_ >> 7;
const uint8_t new_carry = a_ >> 7;
a_ = static_cast<uint8_t>((a_ << 1) | new_carry);
set_rotate_flags();
} break;
case MicroOp::RRCA: {
uint8_t new_carry = a_ & 1;
const uint8_t new_carry = a_ & 1;
a_ = static_cast<uint8_t>((a_ >> 1) | (new_carry << 7));
set_rotate_flags();
} break;
@ -678,7 +696,8 @@ template < class T,
sign_result_ = zero_result_ = bit53_result_ = *static_cast<uint8_t *>(operation->source); \
set_parity(sign_result_); \
half_carry_result_ = 0; \
subtract_flag_ = 0;
subtract_flag_ = 0; \
set_did_compute_flags();
case MicroOp::RLC:
carry_result_ = *static_cast<uint8_t *>(operation->source) >> 7;
@ -693,14 +712,14 @@ template < class T,
break;
case MicroOp::RL: {
uint8_t next_carry = *static_cast<uint8_t *>(operation->source) >> 7;
const uint8_t next_carry = *static_cast<uint8_t *>(operation->source) >> 7;
*static_cast<uint8_t *>(operation->source) = static_cast<uint8_t>((*static_cast<uint8_t *>(operation->source) << 1) | (carry_result_ & Flag::Carry));
carry_result_ = next_carry;
set_shift_flags();
} break;
case MicroOp::RR: {
uint8_t next_carry = *static_cast<uint8_t *>(operation->source);
const uint8_t next_carry = *static_cast<uint8_t *>(operation->source);
*static_cast<uint8_t *>(operation->source) = static_cast<uint8_t>((*static_cast<uint8_t *>(operation->source) >> 1) | (carry_result_ << 7));
carry_result_ = next_carry;
set_shift_flags();
@ -736,11 +755,12 @@ template < class T,
subtract_flag_ = 0; \
half_carry_result_ = 0; \
set_parity(a_); \
bit53_result_ = zero_result_ = sign_result_ = a_;
bit53_result_ = zero_result_ = sign_result_ = a_; \
set_did_compute_flags();
case MicroOp::RRD: {
memptr_.full = hl_.full + 1;
uint8_t low_nibble = a_ & 0xf;
const uint8_t low_nibble = a_ & 0xf;
a_ = (a_ & 0xf0) | (temp8_ & 0xf);
temp8_ = static_cast<uint8_t>((temp8_ >> 4) | (low_nibble << 4));
set_decimal_rotate_flags();
@ -748,7 +768,7 @@ template < class T,
case MicroOp::RLD: {
memptr_.full = hl_.full + 1;
uint8_t low_nibble = a_ & 0xf;
const uint8_t low_nibble = a_ & 0xf;
a_ = (a_ & 0xf0) | (temp8_ >> 4);
temp8_ = static_cast<uint8_t>((temp8_ << 4) | low_nibble);
set_decimal_rotate_flags();
@ -784,12 +804,14 @@ template < class T,
subtract_flag_ = half_carry_result_ = 0;
sign_result_ = zero_result_ = bit53_result_ = *static_cast<uint8_t *>(operation->source);
set_parity(sign_result_);
set_did_compute_flags();
break;
case MicroOp::SetAFlags:
subtract_flag_ = half_carry_result_ = 0;
parity_overflow_result_ = iff2_ ? Flag::Parity : 0;
sign_result_ = zero_result_ = bit53_result_ = a_;
set_did_compute_flags();
break;
case MicroOp::SetZero:
@ -848,6 +870,10 @@ template < class T,
memptr_.full = static_cast<uint16_t>(*static_cast<uint16_t *>(operation->source) + (int8_t)temp8_);
break;
case MicroOp::SetAddrAMemptr:
memptr_.full = static_cast<uint16_t>(((*static_cast<uint16_t *>(operation->source) + 1)&0xff) + (a_ << 8));
break;
case MicroOp::IndexedPlaceHolder:
return;
}

View File

@ -351,7 +351,7 @@ void ProcessorStorage::assemble_base_page(InstructionPage &target, RegisterPair
InstructionTable base_program_table = {
/* 0x00 NOP */ NOP, /* 0x01 LD BC, nn */ StdInstr(Read16Inc(pc_, bc_)),
/* 0x02 LD (BC), A */ StdInstr({MicroOp::Move16, &bc_.full, &memptr_.full}, Write3(memptr_, a_)),
/* 0x02 LD (BC), A */ StdInstr({MicroOp::SetAddrAMemptr, &bc_.full}, Write3(bc_, a_)),
/* 0x03 INC BC; 0x04 INC B; 0x05 DEC B; 0x06 LD B, n */
INC_INC_DEC_LD(bc_, bc_.bytes.high),
@ -366,7 +366,7 @@ void ProcessorStorage::assemble_base_page(InstructionPage &target, RegisterPair
/* 0x0f RRCA */ StdInstr({MicroOp::RRCA}),
/* 0x10 DJNZ */ Instr(6, ReadInc(pc_, temp8_), {MicroOp::DJNZ}, InternalOperation(10), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}),
/* 0x11 LD DE, nn */ StdInstr(Read16Inc(pc_, de_)),
/* 0x12 LD (DE), A */ StdInstr({MicroOp::Move16, &de_.full, &memptr_.full}, Write3(memptr_, a_)),
/* 0x12 LD (DE), A */ StdInstr({MicroOp::SetAddrAMemptr, &de_.full}, Write3(de_, a_)),
/* 0x13 INC DE; 0x14 INC D; 0x15 DEC D; 0x16 LD D, n */
INC_INC_DEC_LD(de_, de_.bytes.high),
@ -395,7 +395,7 @@ void ProcessorStorage::assemble_base_page(InstructionPage &target, RegisterPair
/* 0x2f CPL */ StdInstr({MicroOp::CPL}),
/* 0x30 JR NC */ JR(TestNC), /* 0x31 LD SP, nn */ StdInstr(Read16Inc(pc_, sp_)),
/* 0x32 LD (nn), A */ StdInstr(Read16Inc(pc_, temp16_), Write3(temp16_, a_)),
/* 0x32 LD (nn), A */ StdInstr(Read16Inc(pc_, temp16_), {MicroOp::SetAddrAMemptr, &temp16_.full}, Write3(temp16_, a_)),
/* 0x33 INC SP */ Instr(8, {MicroOp::Increment16, &sp_.full}),
/* 0x34 INC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Increment8, &temp8_}, Write3(INDEX_ADDR(), temp8_)),
/* 0x35 DEC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Decrement8, &temp8_}, Write3(INDEX_ADDR(), temp8_)),

View File

@ -91,6 +91,8 @@ class ProcessorStorage {
IndexedPlaceHolder,
SetAddrAMemptr,
Reset
};
Type type;
@ -132,6 +134,10 @@ class ProcessorStorage {
uint8_t carry_result_; // the carry flag is set if bit 0 of carry_result_ is set
uint8_t halt_mask_ = 0xff;
int flag_adjustment_history_ = 0; // a shifting record of whether each opcode set any flags; it turns out
// that knowledge of what the last opcode did is necessary to get bits 5 & 3
// correct for SCF and CCF.
HalfCycles number_of_cycles_;
enum Interrupt: uint8_t {