mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-26 08:29:33 +00:00
Transfers full TOD responsibility onto the chip-specific templates.
This commit is contained in:
parent
0245b040b0
commit
6210605bc7
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user