mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-25 18:30:21 +00:00
Merge pull request #366 from TomHarte/MoreMemptr
Improves Z80 memptr behaviour.
This commit is contained in:
commit
53f05efb2d
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_)),
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user