2021-07-18 16:23:47 +00:00
|
|
|
//
|
|
|
|
// 6526Storage.hpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 18/07/2021.
|
|
|
|
// Copyright © 2021 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef _526Storage_h
|
|
|
|
#define _526Storage_h
|
|
|
|
|
|
|
|
namespace MOS {
|
|
|
|
namespace MOS6526 {
|
|
|
|
|
|
|
|
struct MOS6526Storage {
|
2021-07-24 01:24:07 +00:00
|
|
|
HalfCycles half_divider_;
|
2021-07-18 16:23:47 +00:00
|
|
|
|
2021-07-24 01:24:07 +00:00
|
|
|
uint8_t output_[2] = {0, 0};
|
|
|
|
uint8_t data_direction_[2] = {0, 0};
|
2021-07-24 01:58:52 +00:00
|
|
|
|
2021-07-24 01:24:07 +00:00
|
|
|
uint8_t interrupt_control_ = 0;
|
2021-07-24 01:58:52 +00:00
|
|
|
uint8_t interrupt_state_ = 0;
|
|
|
|
|
2021-07-24 01:24:07 +00:00
|
|
|
uint32_t tod_increment_mask_ = uint32_t(~0);
|
|
|
|
uint32_t tod_latch_ = 0;
|
|
|
|
uint32_t tod_ = 0;
|
|
|
|
uint32_t tod_alarm_ = 0;
|
|
|
|
|
|
|
|
struct Counter {
|
|
|
|
uint16_t reload = 0;
|
|
|
|
uint16_t value = 0;
|
2021-07-24 02:43:47 +00:00
|
|
|
uint8_t control = 0;
|
|
|
|
|
2021-07-24 20:06:49 +00:00
|
|
|
template <int shift> void set_reload(uint8_t v) {
|
|
|
|
reload = (reload & (0xff00 >> shift)) | uint16_t(v << shift);
|
|
|
|
|
2021-08-02 01:09:02 +00:00
|
|
|
if constexpr (shift == 8) {
|
|
|
|
if(!(control&1)) {
|
|
|
|
pending |= ReloadInOne;
|
|
|
|
}
|
|
|
|
}
|
2021-08-03 20:57:05 +00:00
|
|
|
|
|
|
|
// If this write has hit during a reload cycle, reload.
|
|
|
|
if(pending & ReloadNow) {
|
|
|
|
value = reload;
|
|
|
|
}
|
2021-07-24 20:06:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <bool is_counter_2> void set_control(uint8_t v) {
|
2021-08-02 01:09:02 +00:00
|
|
|
control = v;
|
2021-08-01 22:14:10 +00:00
|
|
|
}
|
|
|
|
|
2021-08-03 01:04:00 +00:00
|
|
|
template <bool is_counter_2> bool advance(bool chained_input) {
|
2021-08-03 20:57:05 +00:00
|
|
|
// TODO: remove most of the conditionals here in favour of bit shuffling.
|
2021-07-26 21:02:30 +00:00
|
|
|
|
2021-08-03 20:57:05 +00:00
|
|
|
pending = (pending & PendingClearMask) << 1;
|
2021-08-01 22:14:10 +00:00
|
|
|
|
2021-08-03 00:14:01 +00:00
|
|
|
//
|
|
|
|
// Apply feeder states inputs: anything that
|
|
|
|
// will take effect in the future.
|
|
|
|
//
|
2021-08-03 01:04:00 +00:00
|
|
|
|
|
|
|
// Schedule a force reload if requested.
|
2021-08-02 01:09:02 +00:00
|
|
|
if(control & 0x10) {
|
2021-08-02 01:35:08 +00:00
|
|
|
pending |= ReloadInOne;
|
2021-08-02 01:09:02 +00:00
|
|
|
control &= ~0x10;
|
2021-07-26 21:02:30 +00:00
|
|
|
}
|
2021-08-03 01:04:00 +00:00
|
|
|
|
|
|
|
// Determine whether an input clock is applicable.
|
|
|
|
if constexpr(is_counter_2) {
|
|
|
|
switch(control&0x60) {
|
|
|
|
case 0x00:
|
|
|
|
pending |= TestInputInOne;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// TODO: all other forms of input.
|
|
|
|
assert(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(!(control&0x20)) {
|
|
|
|
pending |= TestInputNow;
|
|
|
|
} else if (chained_input) { // TODO: check CNT directly, probably?
|
|
|
|
pending |= TestInputInOne;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(pending&TestInputNow && control&1) {
|
2021-08-01 22:14:10 +00:00
|
|
|
pending |= ApplyClockInTwo;
|
|
|
|
}
|
2021-08-03 01:04:00 +00:00
|
|
|
|
|
|
|
// Keep a history of the one-shot bit.
|
2021-08-01 22:14:10 +00:00
|
|
|
if(control & 0x08) {
|
2021-08-03 01:04:00 +00:00
|
|
|
pending |= OneShotInOne | OneShotNow;
|
2021-08-01 22:14:10 +00:00
|
|
|
}
|
2021-07-24 02:43:47 +00:00
|
|
|
|
2021-08-01 22:14:10 +00:00
|
|
|
|
2021-08-03 00:14:01 +00:00
|
|
|
//
|
|
|
|
// Perform a timer tick and decide whether a reload is prompted.
|
|
|
|
//
|
2021-08-01 22:14:10 +00:00
|
|
|
if(pending & ApplyClockNow) {
|
|
|
|
--value;
|
2021-08-03 00:14:01 +00:00
|
|
|
}
|
2021-08-03 01:04:00 +00:00
|
|
|
|
2021-08-03 00:14:01 +00:00
|
|
|
const bool should_reload = !value && (pending & ApplyClockInOne);
|
|
|
|
|
|
|
|
// Schedule a reload if so ordered.
|
|
|
|
if(should_reload) {
|
|
|
|
pending |= ReloadNow; // Combine this decision with a deferred
|
|
|
|
// input from the force-reoad test above.
|
|
|
|
|
|
|
|
// If this was one-shot, stop.
|
|
|
|
if(pending&(OneShotInOne | OneShotNow)) {
|
|
|
|
control &= ~1;
|
2021-08-03 01:04:00 +00:00
|
|
|
pending &= ~(ApplyClockInOne|ApplyClockInTwo); // Cancel scheculed ticks.
|
2021-08-03 00:14:01 +00:00
|
|
|
}
|
2021-07-24 02:43:47 +00:00
|
|
|
}
|
2021-08-02 01:09:02 +00:00
|
|
|
|
2021-08-03 00:14:01 +00:00
|
|
|
// Reload if scheduled.
|
|
|
|
if(pending & ReloadNow) {
|
|
|
|
value = reload;
|
2021-08-03 01:04:00 +00:00
|
|
|
pending &= ~ApplyClockInOne; // Skip next decrement.
|
2021-08-02 01:09:02 +00:00
|
|
|
}
|
2021-08-02 01:35:08 +00:00
|
|
|
|
2021-08-03 00:14:01 +00:00
|
|
|
|
|
|
|
return should_reload;
|
2021-07-24 02:43:47 +00:00
|
|
|
}
|
2021-08-01 22:14:10 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
int pending = 0;
|
|
|
|
|
2021-08-03 01:04:00 +00:00
|
|
|
static constexpr int ReloadInOne = 1 << 0;
|
|
|
|
static constexpr int ReloadNow = 1 << 1;
|
|
|
|
|
|
|
|
static constexpr int OneShotInOne = 1 << 2;
|
|
|
|
static constexpr int OneShotNow = 1 << 3;
|
2021-08-01 22:14:10 +00:00
|
|
|
|
2021-08-03 01:04:00 +00:00
|
|
|
static constexpr int ApplyClockInTwo = 1 << 4;
|
|
|
|
static constexpr int ApplyClockInOne = 1 << 5;
|
|
|
|
static constexpr int ApplyClockNow = 1 << 6;
|
2021-08-01 22:14:10 +00:00
|
|
|
|
2021-08-03 01:04:00 +00:00
|
|
|
static constexpr int TestInputInOne = 1 << 7;
|
|
|
|
static constexpr int TestInputNow = 1 << 8;
|
2021-08-01 22:14:10 +00:00
|
|
|
|
2021-08-02 01:09:02 +00:00
|
|
|
static constexpr int PendingClearMask = ~(ReloadNow | OneShotNow | ApplyClockNow);
|
2021-08-01 22:14:10 +00:00
|
|
|
|
|
|
|
bool active_ = false;
|
2021-07-24 02:43:47 +00:00
|
|
|
} counter_[2];
|
2021-08-02 01:09:02 +00:00
|
|
|
|
|
|
|
static constexpr int InterruptInOne = 1 << 0;
|
|
|
|
static constexpr int InterruptNow = 1 << 1;
|
|
|
|
static constexpr int PendingClearMask = ~(InterruptNow);
|
|
|
|
int pending_ = 0;
|
2021-07-18 16:23:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* _526Storage_h */
|