1
0
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:
Thomas Harte 2019-07-08 15:29:34 -04:00
parent 210bcaa56d
commit 28de629c08
4 changed files with 29 additions and 35 deletions

View File

@ -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();

View File

@ -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);

View File

@ -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.

View File

@ -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));