mirror of
https://github.com/TomHarte/CLK.git
synced 2024-07-07 23:29:06 +00:00
Fixes the 6522 sufficiently to fix keyboard input.
This commit is contained in:
parent
210bcaa56d
commit
28de629c08
@ -91,13 +91,14 @@ template <typename T> void MOS6522<T>::set_register(int address, uint8_t value)
|
|||||||
case 0xa:
|
case 0xa:
|
||||||
registers_.shift = value;
|
registers_.shift = value;
|
||||||
shift_bits_remaining_ = 8;
|
shift_bits_remaining_ = 8;
|
||||||
|
registers_.interrupt_flags &= ~InterruptFlag::ShiftRegister;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Control
|
// Control
|
||||||
case 0xb: {
|
case 0xb:
|
||||||
registers_.auxiliary_control = value;
|
registers_.auxiliary_control = value;
|
||||||
evaluate_cb2_output();
|
evaluate_cb2_output();
|
||||||
} break;
|
break;
|
||||||
case 0xc: {
|
case 0xc: {
|
||||||
// const auto old_peripheral_control = registers_.peripheral_control;
|
// const auto old_peripheral_control = registers_.peripheral_control;
|
||||||
registers_.peripheral_control = value;
|
registers_.peripheral_control = value;
|
||||||
@ -239,10 +240,10 @@ template <typename T> void MOS6522<T>::set_control_line_input(Port port, Line li
|
|||||||
// If this is a transition on CB1, consider updating the shift register.
|
// If this is a transition on CB1, consider updating the shift register.
|
||||||
// TODO: and at least one full clock since the shift register was written?
|
// TODO: and at least one full clock since the shift register was written?
|
||||||
if(port == Port::B) {
|
if(port == Port::B) {
|
||||||
switch((registers_.auxiliary_control >> 2)&7) {
|
switch(shift_mode()) {
|
||||||
default: break;
|
default: break;
|
||||||
case 3: if(value) shift_in(); break; // Shifts in are captured on a low-to-high transition.
|
case ShiftMode::InUnderCB1: if(value) shift_in(); break; // Shifts in are captured on a low-to-high transition.
|
||||||
case 7: if(!value) shift_out(); break; // Shifts out are updated on a high-to-low transition.
|
case ShiftMode::OutUnderCB1: if(!value) shift_out(); break; // Shifts out are updated on a high-to-low transition.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,6 +293,13 @@ template <typename T> void MOS6522<T>::do_phase2() {
|
|||||||
if(handshake_modes_[0] == HandshakeMode::Pulse) {
|
if(handshake_modes_[0] == HandshakeMode::Pulse) {
|
||||||
set_control_line_output(Port::A, Line::Two, LineState::On);
|
set_control_line_output(Port::A, Line::Two, LineState::On);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the shift register is shifting according to the input clock, do a shift.
|
||||||
|
switch(shift_mode()) {
|
||||||
|
default: break;
|
||||||
|
case ShiftMode::InUnderPhase2: shift_in(); break;
|
||||||
|
case ShiftMode::OutUnderPhase2: shift_out(); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> void MOS6522<T>::do_phase1() {
|
template <typename T> void MOS6522<T>::do_phase1() {
|
||||||
@ -303,11 +311,11 @@ template <typename T> void MOS6522<T>::do_phase1() {
|
|||||||
|
|
||||||
// If the shift register is shifting according to this timer, do a shift.
|
// If the shift register is shifting according to this timer, do a shift.
|
||||||
// TODO: "shift register is driven by only the low order 8 bits of timer 2"?
|
// TODO: "shift register is driven by only the low order 8 bits of timer 2"?
|
||||||
switch((registers_.auxiliary_control >> 2)&7) {
|
switch(shift_mode()) {
|
||||||
default: break;
|
default: break;
|
||||||
case 1: shift_in(); break;
|
case ShiftMode::InUnderT2: shift_in(); break;
|
||||||
case 4: shift_out(); break;
|
case ShiftMode::OutUnderT2FreeRunning: shift_out(); break;
|
||||||
case 5: shift_out(); break; // TODO: present a clock on CB1.
|
case ShiftMode::OutUnderT2: shift_out(); break; // TODO: present a clock on CB1.
|
||||||
}
|
}
|
||||||
|
|
||||||
registers_.interrupt_flags |= InterruptFlag::Timer2;
|
registers_.interrupt_flags |= InterruptFlag::Timer2;
|
||||||
@ -331,13 +339,6 @@ template <typename T> void MOS6522<T>::do_phase1() {
|
|||||||
bus_handler_.set_port_output(Port::B, registers_.output[1], registers_.data_direction[1]);
|
bus_handler_.set_port_output(Port::B, registers_.output[1], registers_.data_direction[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the shift register is shifting according to the input clock, do a shift.
|
|
||||||
switch((registers_.auxiliary_control >> 2)&7) {
|
|
||||||
default: break;
|
|
||||||
case 2: shift_in(); break;
|
|
||||||
case 6: shift_out(); break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Runs for a specified number of half cycles. */
|
/*! Runs for a specified number of half cycles. */
|
||||||
@ -389,7 +390,7 @@ template <typename T> void MOS6522<T>::evaluate_cb2_output() {
|
|||||||
// peripheral control register.
|
// peripheral control register.
|
||||||
|
|
||||||
// My guess: other CB2 functions work only if the shift register is disabled (?).
|
// My guess: other CB2 functions work only if the shift register is disabled (?).
|
||||||
if((registers_.auxiliary_control >> 2)&7) {
|
if(shift_mode() != ShiftMode::Disabled) {
|
||||||
// Shift register is enabled, one way or the other; but announce only output.
|
// Shift register is enabled, one way or the other; but announce only output.
|
||||||
if(is_shifting_out()) {
|
if(is_shifting_out()) {
|
||||||
// Output mode; set the level according to the current top of the shift register.
|
// Output mode; set the level according to the current top of the shift register.
|
||||||
@ -435,7 +436,7 @@ template <typename T> void MOS6522<T>::shift_in() {
|
|||||||
template <typename T> void MOS6522<T>::shift_out() {
|
template <typename T> void MOS6522<T>::shift_out() {
|
||||||
// When shifting out, the shift register rotates rather than strictly shifts.
|
// When shifting out, the shift register rotates rather than strictly shifts.
|
||||||
// TODO: is that true for all modes?
|
// TODO: is that true for all modes?
|
||||||
if(shift_mode() == ShiftMode::ShiftOutUnderT2FreeRunning || shift_bits_remaining_) {
|
if(shift_mode() == ShiftMode::OutUnderT2FreeRunning || shift_bits_remaining_) {
|
||||||
registers_.shift = uint8_t((registers_.shift << 1) | (registers_.shift >> 7));
|
registers_.shift = uint8_t((registers_.shift << 1) | (registers_.shift >> 7));
|
||||||
evaluate_cb2_output();
|
evaluate_cb2_output();
|
||||||
|
|
||||||
|
@ -71,13 +71,13 @@ class MOS6522Storage {
|
|||||||
|
|
||||||
enum class ShiftMode {
|
enum class ShiftMode {
|
||||||
Disabled = 0,
|
Disabled = 0,
|
||||||
ShiftInUnderT2 = 1,
|
InUnderT2 = 1,
|
||||||
ShiftInUnderPhase2 = 2,
|
InUnderPhase2 = 2,
|
||||||
ShiftInUnderCB1 = 3,
|
InUnderCB1 = 3,
|
||||||
ShiftOutUnderT2FreeRunning = 4,
|
OutUnderT2FreeRunning = 4,
|
||||||
ShiftOutUnderT2 = 5,
|
OutUnderT2 = 5,
|
||||||
ShiftOutUnderPhase2 = 6,
|
OutUnderPhase2 = 6,
|
||||||
ShiftOutUnderCB1 = 7
|
OutUnderCB1 = 7
|
||||||
};
|
};
|
||||||
ShiftMode shift_mode() const {
|
ShiftMode shift_mode() const {
|
||||||
return ShiftMode((registers_.auxiliary_control >> 2) & 7);
|
return ShiftMode((registers_.auxiliary_control >> 2) & 7);
|
||||||
|
@ -28,7 +28,6 @@ class Keyboard {
|
|||||||
computer signals that it is ready to begin communication by pulling the Keyboard Data line low."
|
computer signals that it is ready to begin communication by pulling the Keyboard Data line low."
|
||||||
*/
|
*/
|
||||||
if(!data) {
|
if(!data) {
|
||||||
// printf("Accepting new command\n");
|
|
||||||
mode_ = Mode::AcceptingCommand;
|
mode_ = Mode::AcceptingCommand;
|
||||||
phase_ = 0;
|
phase_ = 0;
|
||||||
command_ = 0;
|
command_ = 0;
|
||||||
@ -85,7 +84,6 @@ class Keyboard {
|
|||||||
clock_output_ = offset >= 18;
|
clock_output_ = offset >= 18;
|
||||||
|
|
||||||
if(offset == 26) {
|
if(offset == 26) {
|
||||||
// printf("Latched %d\n", (data_input_ ? 1 : 0));
|
|
||||||
command_ = (command_ << 1) | (data_input_ ? 1 : 0);
|
command_ = (command_ << 1) | (data_input_ ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,12 +97,12 @@ class Keyboard {
|
|||||||
|
|
||||||
case Mode::AwaitingEndOfCommand:
|
case Mode::AwaitingEndOfCommand:
|
||||||
// Time out if the end-of-command seems not to be forthcoming.
|
// Time out if the end-of-command seems not to be forthcoming.
|
||||||
|
// This is an elaboration on my part; a guess.
|
||||||
++phase_;
|
++phase_;
|
||||||
if(phase_ == 1000) {
|
if(phase_ == 1000) {
|
||||||
clock_output_ = false;
|
clock_output_ = false;
|
||||||
mode_ = Mode::Waiting;
|
mode_ = Mode::Waiting;
|
||||||
phase_ = 0;
|
phase_ = 0;
|
||||||
// printf("Timed out\n");
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -116,7 +114,6 @@ class Keyboard {
|
|||||||
if(phase_ == 25000 || command_ != 0x10 || response_ != 0x7b) {
|
if(phase_ == 25000 || command_ != 0x10 || response_ != 0x7b) {
|
||||||
mode_ = Mode::SendingResponse;
|
mode_ = Mode::SendingResponse;
|
||||||
phase_ = 0;
|
phase_ = 0;
|
||||||
// printf("Starting response\n");
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -139,7 +136,6 @@ class Keyboard {
|
|||||||
clock_output_ = false;
|
clock_output_ = false;
|
||||||
mode_ = Mode::Waiting;
|
mode_ = Mode::Waiting;
|
||||||
phase_ = 0;
|
phase_ = 0;
|
||||||
// printf("Waiting\n");
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
@ -154,8 +150,6 @@ class Keyboard {
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
int perform_command(int command) {
|
int perform_command(int command) {
|
||||||
// printf("Keyboard: %02x\n", command);
|
|
||||||
|
|
||||||
switch(command) {
|
switch(command) {
|
||||||
case 0x10: // Inquiry.
|
case 0x10: // Inquiry.
|
||||||
case 0x14: { // Instant.
|
case 0x14: { // Instant.
|
||||||
|
@ -511,7 +511,6 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
|
|||||||
CA1 is used for receiving vsync.
|
CA1 is used for receiving vsync.
|
||||||
*/
|
*/
|
||||||
if(port == Port::B && line == Line::Two) {
|
if(port == Port::B && line == Line::Two) {
|
||||||
printf("Keyboard input: %c\n", value ? 't' : 'f');
|
|
||||||
keyboard_.set_input(value);
|
keyboard_.set_input(value);
|
||||||
}
|
}
|
||||||
else printf("Unhandled control line output: %c %d\n", port ? 'B' : 'A', int(line));
|
else printf("Unhandled control line output: %c %d\n", port ? 'B' : 'A', int(line));
|
||||||
|
Loading…
Reference in New Issue
Block a user