mirror of
https://github.com/TomHarte/CLK.git
synced 2026-04-25 11:17:26 +00:00
Implements time-of-day counters, provisionally.
Interrupts to do.
This commit is contained in:
@@ -17,14 +17,14 @@ namespace MOS6526 {
|
||||
|
||||
template <typename BusHandlerT, Personality personality>
|
||||
template <int port> void MOS6526<BusHandlerT, personality>::set_port_output() {
|
||||
const uint8_t output = registers_.output[port] | (~registers_.data_direction[port]);
|
||||
const uint8_t output = output_[port] | (~data_direction_[port]);
|
||||
port_handler_.set_port_output(Port(port), output);
|
||||
}
|
||||
|
||||
template <typename BusHandlerT, Personality personality>
|
||||
template <int port> uint8_t MOS6526<BusHandlerT, personality>::get_port_input() {
|
||||
const uint8_t input = port_handler_.get_port_input(Port(port));
|
||||
return (input & ~registers_.data_direction[port]) | (registers_.output[port] & registers_.data_direction[port]);
|
||||
return (input & ~data_direction_[port]) | (output_[port] & data_direction_[port]);
|
||||
}
|
||||
|
||||
template <typename BusHandlerT, Personality personality>
|
||||
@@ -37,40 +37,85 @@ void MOS6526<BusHandlerT, personality>::write(int address, uint8_t value) {
|
||||
switch(address) {
|
||||
// Port output.
|
||||
case 0:
|
||||
registers_.output[0] = value;
|
||||
output_[0] = value;
|
||||
set_port_output<0>();
|
||||
break;
|
||||
case 1:
|
||||
registers_.output[1] = value;
|
||||
output_[1] = value;
|
||||
set_port_output<1>();
|
||||
break;
|
||||
|
||||
// Port direction.
|
||||
case 2:
|
||||
registers_.data_direction[0] = value;
|
||||
data_direction_[0] = value;
|
||||
set_port_output<0>();
|
||||
break;
|
||||
case 3:
|
||||
registers_.data_direction[1] = value;
|
||||
data_direction_[1] = value;
|
||||
set_port_output<1>();
|
||||
break;
|
||||
|
||||
// Counters; writes set the reload values.
|
||||
case 4: counters_[0].reload = (counters_[0].reload & 0xff00) | uint16_t(value << 0); break;
|
||||
case 5: counters_[0].reload = (counters_[0].reload & 0x00ff) | uint16_t(value << 8); break;
|
||||
case 6: counters_[1].reload = (counters_[1].reload & 0xff00) | uint16_t(value << 0); break;
|
||||
case 7: counters_[1].reload = (counters_[1].reload & 0x00ff) | uint16_t(value << 8); 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) {
|
||||
tod_ = (tod_ & 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) {
|
||||
tod_ = (tod_ & 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) {
|
||||
tod_ = (tod_ & 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;
|
||||
|
||||
// Interrupt control.
|
||||
case 13:
|
||||
registers_.interrupt_control_ = value;
|
||||
interrupt_control_ = value;
|
||||
update_interrupts();
|
||||
break;
|
||||
|
||||
// Control.
|
||||
case 14:
|
||||
case 15:
|
||||
registers_.control[address - 14] = value;
|
||||
control_[address - 14] = value;
|
||||
printf("Ignoring control write: %02x to %d\n", value, address);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unhandled 6526 write: %02x to %d\n", value, address);
|
||||
// assert(false);
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -81,17 +126,72 @@ uint8_t MOS6526<BusHandlerT, personality>::read(int address) {
|
||||
switch(address) {
|
||||
case 0: return get_port_input<0>();
|
||||
case 1: return get_port_input<1>();
|
||||
case 13: return registers_.interrupt_control_;
|
||||
case 13: return interrupt_control_;
|
||||
|
||||
case 2: case 3:
|
||||
return registers_.data_direction[address - 2];
|
||||
return data_direction_[address - 2];
|
||||
|
||||
// Counters; reads obtain the current values.
|
||||
case 4: return uint8_t(counters_[0].value >> 0);
|
||||
case 5: return uint8_t(counters_[0].value >> 8);
|
||||
case 6: return uint8_t(counters_[1].value >> 0);
|
||||
case 7: return uint8_t(counters_[1].value >> 0);
|
||||
|
||||
case 14: case 15:
|
||||
return registers_.control[address - 14];
|
||||
return control_[address - 14];
|
||||
|
||||
// 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_ & 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_ >> 8) & 0xff;
|
||||
}
|
||||
} else {
|
||||
printf("6526 TOD clock not implemented\n");
|
||||
assert(false);
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
if constexpr (personality == Personality::P8250) {
|
||||
tod_latch_ = tod_ | 0xff00'0000;
|
||||
return (tod_ >> 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;
|
||||
|
||||
default:
|
||||
printf("Unhandled 6526 read from %d\n", address);
|
||||
// assert(false);
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
return 0xff;
|
||||
@@ -99,9 +199,26 @@ uint8_t MOS6526<BusHandlerT, personality>::read(int address) {
|
||||
|
||||
template <typename BusHandlerT, Personality personality>
|
||||
void MOS6526<BusHandlerT, personality>::run_for(const HalfCycles half_cycles) {
|
||||
(void)half_cycles;
|
||||
half_divider_ += half_cycles;
|
||||
const int sub = half_divider_.divide_cycles().template as<int>();
|
||||
|
||||
// TODO: apply to timers, depending on mode.
|
||||
(void)sub;
|
||||
}
|
||||
|
||||
template <typename BusHandlerT, Personality personality>
|
||||
void MOS6526<BusHandlerT, personality>::advance_tod(int count) {
|
||||
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.
|
||||
tod_ += uint32_t(count) & tod_increment_mask_;
|
||||
} else {
|
||||
// The 6526 uses a time-of-day clock. This may or may not
|
||||
// be accurate.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user