1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-22 12:33:29 +00:00

Shifts size-limiting of X and Y to transitions and mutations, away from reads.

Primarily to remove potential bug-causing complexity — this is easier to debug. But let's see.
This commit is contained in:
Thomas Harte 2020-11-04 20:35:41 -05:00
parent e3147b6b45
commit d3c7253981
6 changed files with 69 additions and 81 deletions

View File

@ -392,6 +392,9 @@ class ConcreteMachine:
}
}
if(operation == CPU::WDC65816::BusOperation::ReadOpcode && address == 0x00fa56) {
printf("?");
}
// log |= (address >= 0xffa6d9) && (address < 0xffa6ec);
if(log) {
printf("%06x %s %02x", address, isReadOperation(operation) ? "->" : "<-", *value);
@ -405,7 +408,8 @@ class ConcreteMachine:
m65816_.get_value_of_register(CPU::WDC65816::Register::Flags),
m65816_.get_value_of_register(CPU::WDC65816::Register::DataBank),
m65816_.get_value_of_register(CPU::WDC65816::Register::ProgramBank),
m65816_.get_value_of_register(CPU::WDC65816::Register::Direct)
m65816_.get_value_of_register(CPU::WDC65816::Register::Direct
)
);
} else printf("\n");
}

View File

@ -275,6 +275,8 @@ class MemoryMap {
e0_region.read = language_state.read ? ram : rom;
e0_region.write = language_state.write ? nullptr : ram;
if(!bank_base) printf("eo region read: %d!\n", language_state.read);
// Assert assumptions made above re: memory layout.
assert(region_map[bank_base | 0xd0] + 1 == region_map[bank_base | 0xe0]);
assert(region_map[bank_base | 0xe0] == region_map[bank_base | 0xff]);
@ -290,6 +292,7 @@ class MemoryMap {
};
if(inhibit_banks0001) {
printf("Language card: disabled!\n");
set_no_card(0x0000);
set_no_card(0x0100);
} else {

View File

@ -17,8 +17,8 @@ uint16_t ProcessorBase::get_value_of_register(Register r) const {
case Register::StackPointer: return registers_.s.full & (registers_.emulation_flag ? 0xff : 0xffff);
case Register::Flags: return get_flags();
case Register::A: return registers_.a.full;
case Register::X: return registers_.x.full & registers_.x_masks[1];
case Register::Y: return registers_.y.full & registers_.x_masks[1];
case Register::X: return registers_.x.full;
case Register::Y: return registers_.y.full;
case Register::EmulationFlag: return registers_.emulation_flag;
case Register::DataBank: return registers_.data_bank >> 16;
case Register::ProgramBank: return registers_.program_bank >> 16;
@ -33,8 +33,8 @@ void ProcessorBase::set_value_of_register(Register r, uint16_t value) {
case Register::StackPointer: registers_.s.full = value; break;
case Register::Flags: set_flags(uint8_t(value)); break;
case Register::A: registers_.a.full = value; break;
case Register::X: registers_.x.full = value; break;
case Register::Y: registers_.y.full = value; break;
case Register::X: registers_.x.full = value & registers_.x_mask; break;
case Register::Y: registers_.y.full = value & registers_.x_mask; break;
case Register::EmulationFlag: set_emulation_mode(value); break;
case Register::DataBank: registers_.data_bank = uint32_t(value & 0xff) << 16; break;
case Register::ProgramBank: registers_.program_bank = uint32_t(value &0xff) << 16; break;

View File

@ -19,8 +19,6 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
#define m_flag() registers_.mx_flags[0]
#define x_flag() registers_.mx_flags[1]
#define x() (registers_.x.full & registers_.x_masks[1])
#define y() (registers_.y.full & registers_.x_masks[1])
#define stack_address() ((registers_.s.full & registers_.e_masks[1]) | (0x0100 & registers_.e_masks[0]))
Cycles number_of_cycles = cycles + cycles_left_to_run_;
@ -143,15 +141,15 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
break;
case CycleFetchBlockX:
read(((instruction_buffer_.value & 0xff00) << 8) | x(), data_buffer_.any_byte());
read(((instruction_buffer_.value & 0xff00) << 8) | registers_.x.full, data_buffer_.any_byte());
break;
case CycleFetchBlockY:
perform_bus(((instruction_buffer_.value & 0xff00) << 8) | y(), &bus_throwaway_, MOS6502Esque::InternalOperationRead);
perform_bus(((instruction_buffer_.value & 0xff00) << 8) | registers_.y.full, &bus_throwaway_, MOS6502Esque::InternalOperationRead);
break;
case CycleStoreBlockY:
write(((instruction_buffer_.value & 0xff00) << 8) | y(), data_buffer_.any_byte());
write(((instruction_buffer_.value & 0xff00) << 8) | registers_.y.full, data_buffer_.any_byte());
break;
#undef increment_data_address
@ -266,18 +264,18 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
// Used for JMP and JSR (absolute, x).
case OperationConstructAbsoluteIndexedIndirect:
data_address_ = registers_.program_bank + ((instruction_buffer_.value + x()) & 0xffff);
data_address_ = registers_.program_bank + ((instruction_buffer_.value + registers_.x.full) & 0xffff);
data_address_increment_mask_ = 0x00'ff'ff;
continue;
case OperationConstructAbsoluteLongX:
data_address_ = instruction_buffer_.value + x();
data_address_ = instruction_buffer_.value + registers_.x.full;
data_address_increment_mask_ = 0xff'ff'ff;
continue;
case OperationConstructAbsoluteXRead:
case OperationConstructAbsoluteX:
data_address_ = instruction_buffer_.value + x() + registers_.data_bank;
data_address_ = instruction_buffer_.value + registers_.x.full + registers_.data_bank;
incorrect_data_address_ = (data_address_ & 0xff) | (instruction_buffer_.value & 0xff00) + registers_.data_bank;
// If the incorrect address isn't actually incorrect, skip its usage.
@ -289,7 +287,7 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
case OperationConstructAbsoluteYRead:
case OperationConstructAbsoluteY:
data_address_ = instruction_buffer_.value + y() + registers_.data_bank;
data_address_ = instruction_buffer_.value + registers_.y.full + registers_.data_bank;
incorrect_data_address_ = (data_address_ & 0xff) + (instruction_buffer_.value & 0xff00) + registers_.data_bank;
// If the incorrect address isn't actually incorrect, skip its usage.
@ -326,7 +324,7 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
case OperationConstructDirectIndexedIndirect:
data_address_ = registers_.data_bank + (
((registers_.direct + x() + instruction_buffer_.value) & registers_.e_masks[1]) +
((registers_.direct + registers_.x.full + instruction_buffer_.value) & registers_.e_masks[1]) +
(registers_.direct & registers_.e_masks[0])
) & 0xffff;
data_address_increment_mask_ = 0x00'ff'ff;
@ -337,7 +335,7 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
continue;
case OperationConstructDirectIndirectIndexedLong:
data_address_ = y() + data_buffer_.value;
data_address_ = registers_.y.full + data_buffer_.value;
data_address_increment_mask_ = 0xff'ff'ff;
data_buffer_.clear();
continue;
@ -353,7 +351,7 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
case OperationConstructDirectX:
data_address_ = (
(registers_.direct & registers_.e_masks[0]) +
((instruction_buffer_.value + registers_.direct + x()) & registers_.e_masks[1])
((instruction_buffer_.value + registers_.direct + registers_.x.full) & registers_.e_masks[1])
) & 0xffff;
data_address_increment_mask_ = 0x00'ff'ff;
@ -366,7 +364,7 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
case OperationConstructDirectY:
data_address_ = (
(registers_.direct & registers_.e_masks[0]) +
((instruction_buffer_.value + registers_.direct + y()) & registers_.e_masks[1])
((instruction_buffer_.value + registers_.direct + registers_.y.full) & registers_.e_masks[1])
) & 0xffff;
data_address_increment_mask_ = 0x00'ff'ff;
@ -382,7 +380,7 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
continue;
case OperationConstructStackRelativeIndexedIndirect:
data_address_ = registers_.data_bank + data_buffer_.value + y();
data_address_ = registers_.data_bank + data_buffer_.value + registers_.y.full;
data_address_increment_mask_ = 0xff'ff'ff;
data_buffer_.clear();
continue;
@ -458,11 +456,8 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
// Performance.
//
#define LD(dest, src, masks) dest.full = (dest.full & masks[0]) | (src & masks[1])
#define m_top() (instruction_buffer_.value >> registers_.m_shift) & 0xff
#define x_top() (registers_.x.full >> registers_.x_shift) & 0xff
#define y_top() (registers_.y.full >> registers_.x_shift) & 0xff
#define a_top() (registers_.a.full >> registers_.m_shift) & 0xff
#define LDA(src) registers_.a.full = (registers_.a.full & registers_.m_masks[0]) | (src & registers_.m_masks[1])
#define LDXY(dest, src) dest = (src) & registers_.x_mask
case OperationPerform:
switch(active_instruction_->operation) {
@ -472,17 +467,17 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
//
case LDA:
LD(registers_.a, data_buffer_.value, registers_.m_masks);
LDA(data_buffer_.value);
registers_.flags.set_nz(registers_.a.full, registers_.m_shift);
break;
case LDX:
LD(registers_.x, data_buffer_.value, registers_.x_masks);
LDXY(registers_.x, data_buffer_.value);
registers_.flags.set_nz(registers_.x.full, registers_.x_shift);
break;
case LDY:
LD(registers_.y, data_buffer_.value, registers_.x_masks);
LDXY(registers_.y, data_buffer_.value);
registers_.flags.set_nz(registers_.y.full, registers_.x_shift);
break;
@ -511,12 +506,12 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
break;
case STX:
data_buffer_.value = registers_.x.full & registers_.x_masks[1];
data_buffer_.value = registers_.x.full;
data_buffer_.size = 2 - x_flag();
break;
case STY:
data_buffer_.value = registers_.y.full & registers_.x_masks[1];
data_buffer_.value = registers_.y.full;
data_buffer_.size = 2 - x_flag();
break;
@ -554,41 +549,41 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
// (and make reasonable guesses as to the N flag).
case TXS:
registers_.s = registers_.x.full & registers_.x_masks[1];
registers_.s = registers_.x.full;
break;
case TSX:
LD(registers_.x, registers_.s.full, registers_.x_masks);
LDXY(registers_.x, registers_.s.full);
registers_.flags.set_nz(registers_.x.full, registers_.x_shift);
break;
case TXY:
LD(registers_.y, registers_.x.full, registers_.x_masks);
LDXY(registers_.y, registers_.x.full);
registers_.flags.set_nz(registers_.y.full, registers_.x_shift);
break;
case TYX:
LD(registers_.x, registers_.y.full, registers_.x_masks);
LDXY(registers_.x, registers_.y.full);
registers_.flags.set_nz(registers_.x.full, registers_.x_shift);
break;
case TAX:
LD(registers_.x, registers_.a.full, registers_.x_masks);
LDXY(registers_.x, registers_.a.full);
registers_.flags.set_nz(registers_.x.full, registers_.x_shift);
break;
case TAY:
LD(registers_.y, registers_.a.full, registers_.x_masks);
LDXY(registers_.y, registers_.a.full);
registers_.flags.set_nz(registers_.y.full, registers_.x_shift);
break;
case TXA:
LD(registers_.a, registers_.x.full, registers_.m_masks);
LDA(registers_.x.full);
registers_.flags.set_nz(registers_.a.full, registers_.m_shift);
break;
case TYA:
LD(registers_.a, registers_.y.full, registers_.m_masks);
LDA(registers_.y.full);
registers_.flags.set_nz(registers_.a.full, registers_.m_shift);
break;
@ -670,16 +665,16 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
case MVP:
registers_.data_bank = (instruction_buffer_.value & 0xff) << 16;
--registers_.x.full;
--registers_.y.full;
LDXY(registers_.x.full, registers_.x.full - 1);
LDXY(registers_.y.full, registers_.y.full - 1);
if(registers_.a.full) registers_.pc -= 3;
--registers_.a.full;
break;
case MVN:
registers_.data_bank = (instruction_buffer_.value & 0xff) << 16;
++registers_.x.full;
++registers_.y.full;
LDXY(registers_.x.full, registers_.x.full + 1);
LDXY(registers_.y.full, registers_.y.full + 1);
if(registers_.a.full) registers_.pc -= 3;
--registers_.a.full;
break;
@ -725,29 +720,25 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
registers_.flags.set_nz(uint16_t(data_buffer_.value), registers_.m_shift);
break;
case INX: {
const uint16_t x_inc = registers_.x.full + 1;
LD(registers_.x, x_inc, registers_.x_masks);
case INX:
LDXY(registers_.x.full, registers_.x.full + 1);
registers_.flags.set_nz(registers_.x.full, registers_.x_shift);
} break;
break;
case DEX: {
const uint16_t x_dec = registers_.x.full - 1;
LD(registers_.x, x_dec, registers_.x_masks);
case DEX:
LDXY(registers_.x.full, registers_.x.full - 1);
registers_.flags.set_nz(registers_.x.full, registers_.x_shift);
} break;
break;
case INY: {
const uint16_t y_inc = registers_.y.full + 1;
LD(registers_.y, y_inc, registers_.x_masks);
case INY:
LDXY(registers_.y.full, registers_.y.full + 1);
registers_.flags.set_nz(registers_.y.full, registers_.x_shift);
} break;
break;
case DEY: {
const uint16_t y_dec = registers_.y.full - 1;
LD(registers_.y, y_dec, registers_.x_masks);
case DEY:
LDXY(registers_.y.full, registers_.y.full - 1);
registers_.flags.set_nz(registers_.y.full, registers_.x_shift);
} break;
break;
//
// Bitwise operations.
@ -853,15 +844,15 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
// Arithmetic.
//
#define cp(v, shift, masks) {\
const uint32_t temp32 = (v.full & masks[1]) - (data_buffer_.value & masks[1]); \
#define cp(v, shift, mask) {\
const uint32_t temp32 = (v.full & mask) - (data_buffer_.value & mask); \
registers_.flags.set_nz(uint16_t(temp32), shift); \
registers_.flags.carry = ((~temp32) >> (8 + shift))&1; \
}
case CMP: cp(registers_.a, registers_.m_shift, registers_.m_masks); break;
case CPX: cp(registers_.x, registers_.x_shift, registers_.x_masks); break;
case CPY: cp(registers_.y, registers_.x_shift, registers_.x_masks); break;
case CMP: cp(registers_.a, registers_.m_shift, registers_.m_masks[1]); break;
case CPX: cp(registers_.x, registers_.x_shift, registers_.x_mask); break;
case CPY: cp(registers_.y, registers_.x_shift, registers_.x_mask); break;
#undef cp
@ -895,7 +886,7 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
registers_.flags.overflow = (( (decimal_result ^ registers_.a.full) & (~decimal_result ^ data_buffer_.value) ) >> (1 + registers_.m_shift))&0x40;
registers_.flags.set_nz(uint16_t(result), registers_.m_shift);
registers_.flags.carry = ((borrow >> 16)&1)^1;
LD(registers_.a, result, registers_.m_masks);
LDA(result);
break;
}
@ -932,7 +923,7 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
registers_.flags.set_nz(uint16_t(result), registers_.m_shift);
registers_.flags.carry = (result >> (8 + registers_.m_shift))&1;
LD(registers_.a, result, registers_.m_masks);
LDA(result);
} break;
//
@ -950,12 +941,6 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
continue;
}
#undef LD
#undef m_top
#undef x_top
#undef y_top
#undef a_top
// Store a selection as to the exceptions, if any, that would be honoured after this cycle if the
// next thing is a MoveToNextProgram.
selected_exceptions_ = pending_exceptions_ & (registers_.flags.inverse_interrupt | PowerOn | Reset | NMI);
@ -963,6 +948,8 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
}
}
#undef LDA
#undef LDXY
#undef read
#undef write
#undef bus_operation

View File

@ -1109,16 +1109,10 @@ void ProcessorStorage::set_emulation_mode(bool enabled) {
}
void ProcessorStorage::set_m_x_flags(bool m, bool x) {
// Reset the top byte of x and y if _exiting_ 8-bit mode.
// TODO: rationalise this sort of logic, both here and
// with regards to the stack pointer.
if(!x && registers_.mx_flags[1]) {
registers_.x.halves.high = registers_.y.halves.high = 0;
}
registers_.x_masks[0] = x ? 0xff00 : 0x0000;
registers_.x_masks[1] = x ? 0x00ff : 0xffff;
registers_.x_mask = x ? 0x00ff : 0xffff;
registers_.x_shift = x ? 0 : 8;
registers_.x.full &= registers_.x_mask;
registers_.y.full &= registers_.x_mask;
registers_.m_masks[0] = m ? 0xff00 : 0x0000;
registers_.m_masks[1] = m ? 0x00ff : 0xffff;

View File

@ -269,9 +269,9 @@ struct ProcessorStorage {
// Flags aplenty.
MOS6502Esque::LazyFlags flags;
uint8_t mx_flags[2] = {1, 1}; // [0] = m; [1] = x. In both cases either `0` or `1`; `1` => 8-bit.
uint8_t mx_flags[2] = {1, 1}; // [0] = m; [1] = x. In both cases either `0` or `1`; `1` => 8-bit.
uint16_t m_masks[2] = {0xff00, 0x00ff}; // [0] = src mask; [1] = dst mask.
uint16_t x_masks[2] = {0xff00, 0x00ff}; // [0] = src mask; [1] = dst mask.
uint16_t x_mask = 0x00ff; // Just a mask representing the current size of the index registers.
uint16_t e_masks[2] = {0xff00, 0x00ff};
int m_shift = 0;
int x_shift = 0;