2017-09-04 18:26:04 +00:00
|
|
|
//
|
|
|
|
// 6522Storage.hpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 04/09/2017.
|
2018-05-13 19:19:52 +00:00
|
|
|
// Copyright 2017 Thomas Harte. All rights reserved.
|
2017-09-04 18:26:04 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef _522Storage_hpp
|
|
|
|
#define _522Storage_hpp
|
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
|
|
|
namespace MOS {
|
|
|
|
namespace MOS6522 {
|
|
|
|
|
|
|
|
class MOS6522Storage {
|
|
|
|
protected:
|
|
|
|
// Phase toggle
|
|
|
|
bool is_phase2_ = false;
|
|
|
|
|
|
|
|
// The registers
|
|
|
|
struct Registers {
|
2019-05-08 16:35:17 +00:00
|
|
|
// "A low reset (RES) input clears all R6522 internal registers to logic 0"
|
2017-09-04 18:26:04 +00:00
|
|
|
uint8_t output[2] = {0, 0};
|
|
|
|
uint8_t input[2] = {0, 0};
|
|
|
|
uint8_t data_direction[2] = {0, 0};
|
|
|
|
uint16_t timer[2] = {0, 0};
|
|
|
|
uint16_t timer_latch[2] = {0, 0};
|
|
|
|
uint16_t last_timer[2] = {0, 0};
|
|
|
|
int next_timer[2] = {-1, -1};
|
|
|
|
uint8_t shift = 0;
|
|
|
|
uint8_t auxiliary_control = 0;
|
|
|
|
uint8_t peripheral_control = 0;
|
|
|
|
uint8_t interrupt_flags = 0;
|
|
|
|
uint8_t interrupt_enable = 0;
|
2020-09-20 18:51:59 +00:00
|
|
|
|
2017-09-04 18:26:04 +00:00
|
|
|
bool timer_needs_reload = false;
|
2020-09-20 18:51:59 +00:00
|
|
|
uint8_t timer_port_b_output = 0xff;
|
2017-09-04 18:26:04 +00:00
|
|
|
} registers_;
|
|
|
|
|
2019-06-10 13:28:27 +00:00
|
|
|
// Control state.
|
2017-09-04 18:26:04 +00:00
|
|
|
struct {
|
2019-05-08 17:33:22 +00:00
|
|
|
bool lines[2] = {false, false};
|
2019-06-10 13:28:27 +00:00
|
|
|
} control_inputs_[2];
|
|
|
|
|
|
|
|
enum class LineState {
|
|
|
|
On, Off, Input
|
|
|
|
};
|
|
|
|
struct {
|
|
|
|
LineState lines[2] = {LineState::Input, LineState::Input};
|
|
|
|
} control_outputs_[2];
|
2017-09-04 18:26:04 +00:00
|
|
|
|
2019-05-08 16:35:17 +00:00
|
|
|
enum class HandshakeMode {
|
|
|
|
None,
|
|
|
|
Handshake,
|
|
|
|
Pulse
|
|
|
|
} handshake_modes_[2] = { HandshakeMode::None, HandshakeMode::None };
|
|
|
|
|
2017-09-04 18:26:04 +00:00
|
|
|
bool timer_is_running_[2] = {false, false};
|
|
|
|
bool last_posted_interrupt_status_ = false;
|
2019-05-08 19:02:07 +00:00
|
|
|
int shift_bits_remaining_ = 8;
|
2017-09-04 18:26:04 +00:00
|
|
|
|
|
|
|
enum InterruptFlag: uint8_t {
|
|
|
|
CA2ActiveEdge = 1 << 0,
|
|
|
|
CA1ActiveEdge = 1 << 1,
|
|
|
|
ShiftRegister = 1 << 2,
|
|
|
|
CB2ActiveEdge = 1 << 3,
|
|
|
|
CB1ActiveEdge = 1 << 4,
|
|
|
|
Timer2 = 1 << 5,
|
|
|
|
Timer1 = 1 << 6,
|
|
|
|
};
|
2019-07-08 02:13:36 +00:00
|
|
|
|
|
|
|
enum class ShiftMode {
|
|
|
|
Disabled = 0,
|
2019-07-08 19:29:34 +00:00
|
|
|
InUnderT2 = 1,
|
|
|
|
InUnderPhase2 = 2,
|
|
|
|
InUnderCB1 = 3,
|
|
|
|
OutUnderT2FreeRunning = 4,
|
|
|
|
OutUnderT2 = 5,
|
|
|
|
OutUnderPhase2 = 6,
|
|
|
|
OutUnderCB1 = 7
|
2019-07-08 02:13:36 +00:00
|
|
|
};
|
2020-09-23 00:50:39 +00:00
|
|
|
bool timer1_is_controlling_pb7() const {
|
|
|
|
return registers_.auxiliary_control & 0x80;
|
|
|
|
}
|
|
|
|
bool timer1_is_continuous() const {
|
|
|
|
return registers_.auxiliary_control & 0x40;
|
2019-07-08 02:13:36 +00:00
|
|
|
}
|
|
|
|
bool is_shifting_out() const {
|
|
|
|
return registers_.auxiliary_control & 0x10;
|
|
|
|
}
|
2020-09-23 00:50:39 +00:00
|
|
|
int timer2_clock_decrement() const {
|
|
|
|
return 1 ^ ((registers_.auxiliary_control >> 5)&1);
|
|
|
|
}
|
|
|
|
int timer2_pb6_decrement() const {
|
|
|
|
return (registers_.auxiliary_control >> 5)&1;
|
|
|
|
}
|
|
|
|
ShiftMode shift_mode() const {
|
|
|
|
return ShiftMode((registers_.auxiliary_control >> 2) & 7);
|
|
|
|
}
|
|
|
|
bool portb_is_latched() const {
|
|
|
|
return registers_.auxiliary_control & 0x02;
|
|
|
|
}
|
|
|
|
bool port1_is_latched() const {
|
|
|
|
return registers_.auxiliary_control & 0x01;
|
|
|
|
}
|
2017-09-04 18:26:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* _522Storage_hpp */
|