1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-09 05:25:01 +00:00

Steps towards proper calculation of time.

This commit is contained in:
Thomas Harte
2020-11-14 18:39:16 -05:00
parent 73c38b3b0d
commit ec3ff0da12

View File

@@ -177,12 +177,15 @@ class ConcreteMachine:
forceinline Cycles perform_bus_operation(const CPU::WDC65816::BusOperation operation, const uint32_t address, uint8_t *const value) { forceinline Cycles perform_bus_operation(const CPU::WDC65816::BusOperation operation, const uint32_t address, uint8_t *const value) {
const auto &region = MemoryMapRegion(memory_, address); const auto &region = MemoryMapRegion(memory_, address);
static bool log = false; static bool log = false;
bool is_1Mhz = (region.flags & MemoryMap::Region::Is1Mhz) || !(speed_register_ & 0x80) || (speed_register_ & motor_flags_);
if(region.flags & MemoryMap::Region::IsIO) { if(region.flags & MemoryMap::Region::IsIO) {
// Ensure classic auxiliary and language card accesses have effect. // Ensure classic auxiliary and language card accesses have effect.
const bool is_read = isReadOperation(operation); const bool is_read = isReadOperation(operation);
memory_.access(uint16_t(address), is_read); memory_.access(uint16_t(address), is_read);
// TODO: which of these are actually 2.8Mhz?
const auto address_suffix = address & 0xffff; const auto address_suffix = address & 0xffff;
#define ReadWrite(x) (x) | (is_read * 0x10000) #define ReadWrite(x) (x) | (is_read * 0x10000)
#define Read(x) (x) | 0x10000 #define Read(x) (x) | 0x10000
@@ -249,9 +252,18 @@ class ConcreteMachine:
*value = speed_register_; *value = speed_register_;
break; break;
case Write(0xc036): case Write(0xc036):
// b7: 1 => operate at 2.8Mhz; 0 => 1Mhz.
// b6: power-on status; 1 => system has been turned on by the power switch (TODO: what clears this?)
// b5: reserved
// b4: [bank shadowing bit; cf. the memory map]
// b03: motor on-off speed detectors;
// 1 => switch to 1Mhz if motor is on; 0 => don't;
// b0 = slot 4 (i.e. watches addresses c0c9, c0c8)
// b1 = slot 5 (i.e. c0d9, c0d8)
// b2 = slot 6 (i.e. c0e9, c0e8)
// b3 = slot 7 (i.e. c0f9, c0f8)
memory_.set_speed_register(*value); memory_.set_speed_register(*value);
speed_register_ = *value; speed_register_ = *value;
printf("[Unimplemented] most of speed register: %02x\n", *value);
break; break;
// [Memory] State register. // [Memory] State register.
@@ -499,6 +511,18 @@ class ConcreteMachine:
break; break;
default: default:
// Update motor mask bits.
switch(address_suffix) {
case 0xc0c8: motor_flags_ &= ~0x01; break;
case 0xc0c9: motor_flags_ |= 0x01; break;
case 0xc0d8: motor_flags_ &= ~0x02; break;
case 0xc0d9: motor_flags_ |= 0x02; break;
case 0xc0e8: motor_flags_ &= ~0x04; break;
case 0xc0e9: motor_flags_ |= 0x04; break;
case 0xc0f8: motor_flags_ &= ~0x08; break;
case 0xc0f9: motor_flags_ |= 0x08; break;
}
// Check for a card access. // Check for a card access.
if(address_suffix >= 0xc080 && address_suffix < 0xc800) { if(address_suffix >= 0xc080 && address_suffix < 0xc800) {
// This is an abridged version of the similar code in AppleII.cpp from // This is an abridged version of the similar code in AppleII.cpp from
@@ -547,10 +571,7 @@ class ConcreteMachine:
iwm_->write(int(address_suffix), *value); iwm_->write(int(address_suffix), *value);
} }
break; break;
// TODO: 0xc0c8, 0xc0c9, 0xc0d8, 0xc0d9, 0xc0f8, 0xc0f9 drive motors.
} }
// TODO: disk-port soft switches should be in COEx.
// log = true; // log = true;
} }
#undef ReadWrite #undef ReadWrite
@@ -572,6 +593,15 @@ class ConcreteMachine:
if(isReadOperation(operation)) { if(isReadOperation(operation)) {
MemoryMapRead(region, address, value); MemoryMapRead(region, address, value);
} else { } else {
// Shadowed writes also occur "at 1Mhz".
// TODO: this is probably an approximation. I'm assuming that there's the ability asynchronously to post
// both a 1Mhz cycle and a 2.8Mhz cycle and since the latter always fits into the former, this is sufficiently
// descriptive. I suspect this isn't true as it wouldn't explain the speed boost that Wolfenstein and others
// get by adding periodic NOPs within their copy-to-shadow step.
//
// Maybe the interaction with 2.8Mhz refresh isn't as straightforward as I think?
is_1Mhz |= region.flags & MemoryMap::Region::IsShadowed;
// Use a very broad test for flushing video: any write to $e0 or $e1, or any write that is shadowed. // Use a very broad test for flushing video: any write to $e0 or $e1, or any write that is shadowed.
// TODO: at least restrict the e0/e1 test to possible video buffers! // TODO: at least restrict the e0/e1 test to possible video buffers!
if((address >= 0xe00000 && address < 0xe1000000) || region.flags & MemoryMap::Region::IsShadowed) { if((address >= 0xe00000 && address < 0xe1000000) || region.flags & MemoryMap::Region::IsShadowed) {
@@ -604,16 +634,16 @@ class ConcreteMachine:
} else printf("\n"); } else printf("\n");
} }
Cycles duration = Cycles(5); // TODO: fully determine the cost of this access.
// Below is very vague on real details. Won't do.
// TODO: determine the cost of this access. Cycles duration;
// if((mapping.flags & BankMapping::Is1Mhz) || ((mapping.flags & BankMapping::IsShadowed) && !isReadOperation(operation))) { if(is_1Mhz) {
// // TODO: (i) get into phase; (ii) allow for the 1Mhz bus length being sporadically 16 rather than 14. // TODO: (i) get into phase; (ii) allow for the 1Mhz bus length being sporadically 16 rather than 14.
// duration = Cycles(14); duration = Cycles(14);
// } else { } else {
// // TODO: (i) get into phase; (ii) allow for collisions with the refresh cycle. // TODO: (i) get into phase; (ii) allow for collisions with the refresh cycle.
// duration = Cycles(5); duration = Cycles(5);
// } }
fast_access_phase_ = (fast_access_phase_ + duration.as<int>()) % 5; // TODO: modulo something else, to allow for refresh. fast_access_phase_ = (fast_access_phase_ + duration.as<int>()) % 5; // TODO: modulo something else, to allow for refresh.
slow_access_phase_ = (slow_access_phase_ + duration.as<int>()) % 14; // TODO: modulo something else, to allow for stretched cycles. slow_access_phase_ = (slow_access_phase_ + duration.as<int>()) % 14; // TODO: modulo something else, to allow for stretched cycles.
@@ -655,6 +685,7 @@ class ConcreteMachine:
int slow_access_phase_ = 0; int slow_access_phase_ = 0;
uint8_t speed_register_ = 0x40; // i.e. Power-on status. (TODO: only if ROM03?) uint8_t speed_register_ = 0x40; // i.e. Power-on status. (TODO: only if ROM03?)
uint8_t motor_flags_ = 0x00;
// MARK: - Memory storage. // MARK: - Memory storage.