mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-28 22:29:36 +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:
|
||||
registers_.shift = value;
|
||||
shift_bits_remaining_ = 8;
|
||||
registers_.interrupt_flags &= ~InterruptFlag::ShiftRegister;
|
||||
break;
|
||||
|
||||
// Control
|
||||
case 0xb: {
|
||||
case 0xb:
|
||||
registers_.auxiliary_control = value;
|
||||
evaluate_cb2_output();
|
||||
} break;
|
||||
break;
|
||||
case 0xc: {
|
||||
// const auto old_peripheral_control = registers_.peripheral_control;
|
||||
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.
|
||||
// TODO: and at least one full clock since the shift register was written?
|
||||
if(port == Port::B) {
|
||||
switch((registers_.auxiliary_control >> 2)&7) {
|
||||
default: break;
|
||||
case 3: 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.
|
||||
switch(shift_mode()) {
|
||||
default: break;
|
||||
case ShiftMode::InUnderCB1: if(value) shift_in(); break; // Shifts in are captured on a low-to-high 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) {
|
||||
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() {
|
||||
@ -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.
|
||||
// TODO: "shift register is driven by only the low order 8 bits of timer 2"?
|
||||
switch((registers_.auxiliary_control >> 2)&7) {
|
||||
default: break;
|
||||
case 1: shift_in(); break;
|
||||
case 4: shift_out(); break;
|
||||
case 5: shift_out(); break; // TODO: present a clock on CB1.
|
||||
switch(shift_mode()) {
|
||||
default: break;
|
||||
case ShiftMode::InUnderT2: shift_in(); break;
|
||||
case ShiftMode::OutUnderT2FreeRunning: shift_out(); break;
|
||||
case ShiftMode::OutUnderT2: shift_out(); break; // TODO: present a clock on CB1.
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
// 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. */
|
||||
@ -389,7 +390,7 @@ template <typename T> void MOS6522<T>::evaluate_cb2_output() {
|
||||
// peripheral control register.
|
||||
|
||||
// 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.
|
||||
if(is_shifting_out()) {
|
||||
// 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() {
|
||||
// When shifting out, the shift register rotates rather than strictly shifts.
|
||||
// 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));
|
||||
evaluate_cb2_output();
|
||||
|
||||
|
@ -71,13 +71,13 @@ class MOS6522Storage {
|
||||
|
||||
enum class ShiftMode {
|
||||
Disabled = 0,
|
||||
ShiftInUnderT2 = 1,
|
||||
ShiftInUnderPhase2 = 2,
|
||||
ShiftInUnderCB1 = 3,
|
||||
ShiftOutUnderT2FreeRunning = 4,
|
||||
ShiftOutUnderT2 = 5,
|
||||
ShiftOutUnderPhase2 = 6,
|
||||
ShiftOutUnderCB1 = 7
|
||||
InUnderT2 = 1,
|
||||
InUnderPhase2 = 2,
|
||||
InUnderCB1 = 3,
|
||||
OutUnderT2FreeRunning = 4,
|
||||
OutUnderT2 = 5,
|
||||
OutUnderPhase2 = 6,
|
||||
OutUnderCB1 = 7
|
||||
};
|
||||
ShiftMode shift_mode() const {
|
||||
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."
|
||||
*/
|
||||
if(!data) {
|
||||
// printf("Accepting new command\n");
|
||||
mode_ = Mode::AcceptingCommand;
|
||||
phase_ = 0;
|
||||
command_ = 0;
|
||||
@ -85,7 +84,6 @@ class Keyboard {
|
||||
clock_output_ = offset >= 18;
|
||||
|
||||
if(offset == 26) {
|
||||
// printf("Latched %d\n", (data_input_ ? 1 : 0));
|
||||
command_ = (command_ << 1) | (data_input_ ? 1 : 0);
|
||||
}
|
||||
|
||||
@ -99,12 +97,12 @@ class Keyboard {
|
||||
|
||||
case Mode::AwaitingEndOfCommand:
|
||||
// Time out if the end-of-command seems not to be forthcoming.
|
||||
// This is an elaboration on my part; a guess.
|
||||
++phase_;
|
||||
if(phase_ == 1000) {
|
||||
clock_output_ = false;
|
||||
mode_ = Mode::Waiting;
|
||||
phase_ = 0;
|
||||
// printf("Timed out\n");
|
||||
}
|
||||
return;
|
||||
|
||||
@ -116,7 +114,6 @@ class Keyboard {
|
||||
if(phase_ == 25000 || command_ != 0x10 || response_ != 0x7b) {
|
||||
mode_ = Mode::SendingResponse;
|
||||
phase_ = 0;
|
||||
// printf("Starting response\n");
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -139,7 +136,6 @@ class Keyboard {
|
||||
clock_output_ = false;
|
||||
mode_ = Mode::Waiting;
|
||||
phase_ = 0;
|
||||
// printf("Waiting\n");
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@ -154,8 +150,6 @@ class Keyboard {
|
||||
private:
|
||||
|
||||
int perform_command(int command) {
|
||||
// printf("Keyboard: %02x\n", command);
|
||||
|
||||
switch(command) {
|
||||
case 0x10: // Inquiry.
|
||||
case 0x14: { // Instant.
|
||||
|
@ -511,7 +511,6 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
|
||||
CA1 is used for receiving vsync.
|
||||
*/
|
||||
if(port == Port::B && line == Line::Two) {
|
||||
printf("Keyboard input: %c\n", value ? 't' : 'f');
|
||||
keyboard_.set_input(value);
|
||||
}
|
||||
else printf("Unhandled control line output: %c %d\n", port ? 'B' : 'A', int(line));
|
||||
|
Loading…
x
Reference in New Issue
Block a user