1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-25 18:30:07 +00:00

Transfers full TOD responsibility onto the chip-specific templates.

This commit is contained in:
Thomas Harte 2021-08-03 19:10:09 -04:00
parent 0245b040b0
commit 6210605bc7
2 changed files with 111 additions and 123 deletions

View File

@ -73,61 +73,16 @@ void MOS6526<BusHandlerT, personality>::write(int address, uint8_t value) {
break;
// Counters; writes set the reload values.
case 4: counter_[0].template set_reload<0>(value); break;
case 5: counter_[0].template set_reload<8>(value); break;
case 6: counter_[1].template set_reload<0>(value); break;
case 7: counter_[1].template set_reload<8>(value); break;
case 4: counter_[0].template set_reload<0>(value); break;
case 5: counter_[0].template set_reload<8>(value); break;
case 6: counter_[1].template set_reload<0>(value); break;
case 7: counter_[1].template set_reload<8>(value); break;
// Time-of-day clock.
//
// 8520: a binary counter; stopped on any write, restarted
// upon a write to the LSB.
case 8:
if constexpr (personality == Personality::P8250) {
if(counter_[1].control & 0x80) {
tod_.alarm = (tod_.alarm & 0xffff00) | uint32_t(value);
} else {
tod_.value = (tod_.value & 0xffff00) | uint32_t(value);
tod_.increment_mask = uint32_t(~0);
}
} else {
printf("6526 TOD clock not implemented\n");
assert(false);
}
break;
case 9:
if constexpr (personality == Personality::P8250) {
if(counter_[1].control & 0x80) {
tod_.alarm = (tod_.alarm & 0xff00ff) | uint32_t(value << 8);
} else {
tod_.value = (tod_.value & 0xff00ff) | uint32_t(value << 8);
tod_.increment_mask = 0;
}
} else {
printf("6526 TOD clock not implemented\n");
assert(false);
}
break;
case 10:
if constexpr (personality == Personality::P8250) {
if(counter_[1].control & 0x80) {
tod_.alarm = (tod_.alarm & 0x00ffff) | uint32_t(value << 16);
} else {
tod_.value = (tod_.value & 0x00ffff) | uint32_t(value << 16);
tod_.increment_mask = 0;
}
} else {
printf("6526 TOD clock not implemented\n");
assert(false);
}
break;
case 11:
if constexpr (personality != Personality::P8250) {
printf("6526 TOD clock not implemented\n");
assert(false);
}
break;
case 8: tod_.template write<0>(value); break;
case 9: tod_.template write<1>(value); break;
case 10: tod_.template write<2>(value); break;
case 11: tod_.template write<3>(value); break;
// Interrupt control.
case 13: {
@ -139,9 +94,15 @@ void MOS6526<BusHandlerT, personality>::write(int address, uint8_t value) {
update_interrupts();
} break;
// Control.
case 14: counter_[0].template set_control<false>(value); break;
case 15: counter_[1].template set_control<true>(value); break;
// Control. Posted to both the counters and the clock as it affects both.
case 14:
counter_[0].template set_control<false>(value);
tod_.template set_control<false>(value);
break;
case 15:
counter_[1].template set_control<true>(value);
tod_.template set_control<true>(value);
break;
default:
printf("Unhandled 6526 write: %02x to %d\n", value, address);
@ -179,53 +140,10 @@ uint8_t MOS6526<BusHandlerT, personality>::read(int address) {
return counter_[address - 14].control;
// Time-of-day clock.
//
// 8250: Latch on MSB. Unlatch on LSB. Read raw if not latched.
case 8:
if constexpr (personality == Personality::P8250) {
if(tod_.latch) {
const uint8_t result = tod_.latch & 0xff;
tod_.latch = 0;
return result;
} else {
return tod_.value & 0xff;
}
} else {
printf("6526 TOD clock not implemented\n");
assert(false);
}
break;
case 9:
if constexpr (personality == Personality::P8250) {
if(tod_.latch) {
return (tod_.latch >> 8) & 0xff;
} else {
return (tod_.value >> 8) & 0xff;
}
} else {
printf("6526 TOD clock not implemented\n");
assert(false);
}
break;
case 10:
if constexpr (personality == Personality::P8250) {
tod_.latch = tod_.value | 0xff00'0000;
return (tod_.value >> 16) & 0xff;
} else {
printf("6526 TOD clock not implemented\n");
assert(false);
}
break;
case 11:
if constexpr (personality == Personality::P8250) {
return 0x00; // Assumed. Just a guss.
} else {
printf("6526 TOD clock not implemented\n");
assert(false);
}
break;
case 8: return tod_.template read<0>();
case 9: return tod_.template read<1>();
case 10: return tod_.template read<2>();
case 11: return tod_.template read<3>();
default:
printf("Unhandled 6526 read from %d\n", address);
@ -259,18 +177,8 @@ void MOS6526<BusHandlerT, personality>::run_for(const HalfCycles half_cycles) {
template <typename BusHandlerT, Personality personality>
void MOS6526<BusHandlerT, personality>::advance_tod(int count) {
if(!count) return;
if constexpr(personality == Personality::P8250) {
// The 8250 uses a simple binary counter to replace the
// 6526's time-of-day clock. So this is easy.
const uint32_t distance_to_alarm = (tod_.alarm - tod_.value) & 0xffffff;
tod_.value += uint32_t(count) & tod_.increment_mask;
if(distance_to_alarm <= uint32_t(count)) {
posit_interrupt(0x04);
}
} else {
// The 6526 uses a time-of-day clock. This may or may not
// be accurate.
if(tod_.advance(count)) {
posit_interrupt(0x04);
}
}

View File

@ -12,15 +12,95 @@
namespace MOS {
namespace MOS6526 {
template <bool is_8250> struct TODStorage {};
template <> struct TODStorage<false> {
// TODO.
class TODBase {
public:
template <bool is_timer2> void set_control(uint8_t value) {
if constexpr (is_timer2) {
write_alarm = value & 0x80;
} else {
is_50Hz = value & 0x80;
}
}
protected:
bool write_alarm = false, is_50Hz = false;
};
template <> struct TODStorage<true> {
uint32_t increment_mask = uint32_t(~0);
uint32_t latch = 0;
uint32_t value = 0;
uint32_t alarm = 0;
template <bool is_8250> class TODStorage {};
template <> class TODStorage<false>: public TODBase {
public:
// TODO.
template <int byte> void write(uint8_t) {
printf("6526 TOD clock not implemented\n");
assert(false);
}
template <int byte> uint8_t read() {
printf("6526 TOD clock not implemented\n");
assert(false);
}
bool advance(int) {
printf("6526 TOD clock not implemented\n");
assert(false);
}
};
template <> class TODStorage<true>: public TODBase {
private:
uint32_t increment_mask_ = uint32_t(~0);
uint32_t latch_ = 0;
uint32_t value_ = 0;
uint32_t alarm_ = 0;
public:
template <int byte> void write(uint8_t v) {
if constexpr (byte == 3) {
return;
}
constexpr int shift = byte << 3;
// Write to either the alarm or the current value as directed;
// writing to any part of the current value other than the LSB
// pauses incrementing until the LSB is written.
if(write_alarm) {
alarm_ = (alarm_ & (0x00ff'ffff >> (24 - shift))) | uint32_t(v << shift);
} else {
value_ = (alarm_ & (0x00ff'ffff >> (24 - shift))) | uint32_t(v << shift);
increment_mask_ = (shift == 0) ? uint32_t(~0) : 0;
}
}
template <int byte> uint8_t read() {
if constexpr (byte == 3) {
return 0xff; // Assumed. Just a guss.
}
constexpr int shift = byte << 3;
if(latch_) {
// Latching: if this is a latched read from the LSB,
// empty the latch.
const uint8_t result = uint8_t((latch_ >> shift) & 0xff);
if constexpr (shift == 0) {
latch_ = 0;
}
return result;
} else {
// Latching: if this is a read from the MSB, latch now.
if constexpr (shift == 16) {
latch_ = value_ | 0xff00'0000;
}
return uint8_t((value_ >> shift) & 0xff);
}
}
bool advance(int count) {
// The 8250 uses a simple binary counter to replace the
// 6526's time-of-day clock. So this is easy.
const uint32_t distance_to_alarm = (alarm_ - value_) & 0xffffff;
value_ += uint32_t(count) & increment_mask_;
return distance_to_alarm <= uint32_t(count);
}
};
struct MOS6526Storage {