diff --git a/kernel/iec_listener.c b/kernel/iec_listener.c index 810ae36..2314d33 100644 --- a/kernel/iec_listener.c +++ b/kernel/iec_listener.c @@ -108,16 +108,26 @@ static void emit_record(u8 kind, u8 value, u8 flags) /* --- busy-poll helper ---------------------------------------------------- */ /* - * Spin until CLK reaches `want_asserted`, or timeout/ATN/RESET. Caller holds - * local IRQs disabled. Uses a microsecond budget rather than a fixed udelay so - * a slightly-fast C64 is handled correctly (research §1.3). + * Spin until CLK reaches `want_asserted`, or timeout/ATN-change/RESET. Caller + * holds local IRQs disabled. Uses a microsecond budget rather than a fixed + * udelay so a slightly-fast C64 is handled correctly (research §1.3). + * + * The ATN abort is phase-relative, and IEC_RX_ATN means "ATN changed, abort": + * - data_phase: ATN is released; abort if it ASSERTS (C64 interrupts data + * transfer with a new command). + * - command phase: ATN is asserted for the whole command byte; abort if it + * RELEASES (the command sequence is over -> hand back to the state machine). + * Treating any asserted ATN as an abort (the previous behaviour) made command + * reception impossible: ATN is legitimately low the entire command phase, so + * the very first poll aborted before a single bit was clocked. */ -static enum iec_rx wait_clk(bool want_asserted, unsigned int timeout_us) +static enum iec_rx wait_clk(bool want_asserted, unsigned int timeout_us, + bool data_phase) { unsigned int waited = 0; while (iec_clk_asserted() != want_asserted) { - if (iec_atn_asserted()) + if (iec_atn_asserted() == data_phase) return IEC_RX_ATN; if (iec_reset_asserted()) return IEC_RX_RESET; @@ -143,7 +153,7 @@ static enum iec_rx receive_byte(u8 *out, bool *eoi, bool data_phase) *eoi = false; /* 1. READY-FOR-DATA: wait for talker to release CLK, then release DATA */ - rc = wait_clk(false /* released */, IEC_CLK_TIMEOUT_US); + rc = wait_clk(false /* released */, IEC_CLK_TIMEOUT_US, data_phase); if (rc != IEC_RX_OK) return rc; iec_data_release(); @@ -171,10 +181,12 @@ static enum iec_rx receive_byte(u8 *out, bool *eoi, bool data_phase) /* 3. RECEIVE 8 BITS, LSB first */ for (i = 0; i < 8; i++) { - rc = wait_clk(true /* asserted: data invalid/setup */, IEC_CLK_TIMEOUT_US); + rc = wait_clk(true /* asserted: data invalid/setup */, + IEC_CLK_TIMEOUT_US, data_phase); if (rc != IEC_RX_OK) goto out; - rc = wait_clk(false /* released: data valid -> sample */, IEC_CLK_TIMEOUT_US); + rc = wait_clk(false /* released: data valid -> sample */, + IEC_CLK_TIMEOUT_US, data_phase); if (rc != IEC_RX_OK) goto out; /* released(high) = bit 1, asserted(low) = bit 0 */