diff --git a/c64/kernal/iec_pull_data_release_atn_clock.s b/c64/kernal/iec_pull_data_release_atn_clock.s new file mode 100644 index 00000000..0e8822da --- /dev/null +++ b/c64/kernal/iec_pull_data_release_atn_clock.s @@ -0,0 +1,7 @@ + +iec_pull_data_release_atn_clock: + lda CI2PRA + ora #BIT_CI2PRA_DAT_OUT ; pull + and #$FF - BIT_CI2PRA_ATN_OUT - BIT_CI2PRA_CLK_OUT ; release + sta CI2PRA + rts diff --git a/c64/kernal/iec_rx_byte.s b/c64/kernal/iec_rx_byte.s index 0646706d..8caf8392 100644 --- a/c64/kernal/iec_rx_byte.s +++ b/c64/kernal/iec_rx_byte.s @@ -1,118 +1,103 @@ ;; Receive a byte from the IEC bus. - ;; reference http://www.zimmers.net/anonftp/pub/cbm/programming/serial-bus.pdf - ;; page 11. - - -;; XXX rework this, according to pagetable.com + ;; Implemented based on https://www.pagetable.com/?p=1135, https://github.com/mist64/cbmbus_doc, + ;; http://www.zimmers.net/anonftp/pub/cbm/programming/serial-bus.pdf (page 11) iec_rx_byte: + ;; First, we wait for the talker to release the CLK line + jsr iec_wait_for_clk_release + + ;; We then release the DATA to signal we are ready + ;; We can use this routine, since we weren't pulling CLK anyway + jsr iec_release_clk_data + + ;; Wait for talker to pull CLK. + ;; If over 200 usec (205 cycles on NTSC machine) , then it is EOI. + ;; Loop iteraction takes 13 cycles, 17 full iterations are enough + + ldx #$11 ; 2 cycles +iec_rx_clk_wait: + lda CI2PRA ; 4 cycles + rol ; 2 cycles, to put BIT_CI2PRA_CLK_IN as the last bit + bpl iec_rx_not_eoi ; 2 cycles if not jumped + dex ; 2 cycles + bne iec_rx_clk_wait ; 3 cycles if jumped + + ;; Timeout - wait for pulled CLK and pull data for 60 usec to confirm + jsr iec_wait_for_clk_pull + jsr iec_release_clk_pull_data + jsr iec_wait60us + jsr iec_release_clk_data + + ;; Store EOI information in IOSTATUS - XXX this should be done by the caller! + lda IOSTATUS + ora #$40 + sta IOSTATUS + + sec rts -; ;; First, we wait for the talker to release the CLK line. -; ;; XXX jsr iec_wait_for_clock_release +iec_rx_not_eoi: -; ;; We then release the data line -; ;; (We can use this routine, since we weren't holding CLK, anyway) -; jsr iec_release_clk_and_data + ;; Latch input bits in on rising edge of CLK, eight times for eight bits. + ldx #7 -; ;; Wait for talker to assert CLK. -; ;; If >200usec, then it is EOI and we have to assert the -; ;; DATA line for 60 usec to tell the TALKER that we have -; ;; acknowledged the EOI. -; ldx #20 -iec_rx_clk_wait: -; ;; Loop takes 11 usec, so ~20 iterations for 200usec timeout -; lda $dd00 -; rol -; bpl not_eoi -; dex -; cpx #$21 -; bne not_rx_timeout -; ;; Time out waiting for CLK to assert again. -; ;; = error -; sec -; rts -not_rx_timeout: -; cpx #$00 -; bpl iec_rx_clk_wait - -; ;; Remember EOI condition -; lda IOSTATUS -; ora #$40 -; sta IOSTATUS - -; ;; EOI timeout: So pulse DATA line for 60 usec -; jsr iec_assert_data -; jsr iec_wait60us -; jsr iec_release_clk_and_data - -; ;; And still wait for CLK to be asserted -; ;; XXX - This will cause periodic EOI pulses if the sender takes too long. -; ;; That is probably ok. -; ldx #$7f -; jmp iec_rx_clk_wait - -not_eoi: -; ;; CLK is now low. Latch input bits in on rising edge -; ;; of CLK, eight times for eight bits. -; ldx #7 - -; ;; Get empty byte to load into. -; lda #$00 -; pha + ;; Get empty byte to load into. + lda #$00 + pha iec_rx_bit_loop: -; ;; Wait for CLK to release -; ;; jsr iec_wait_for_clock_release -; ;; (we do this implicitly below, with a tighter routine, -; ;; so that we don't have timing problems, as the requirements -; ;; are quite tight. Basically we need to read the clock and data -; ;; bit from the same byte read. + ;; Wait for CLK to release + jsr iec_wait_for_clk_release -; ;; DATA now has the next bit, but inverted (well, except that it turns out not to be). -; ;; DATA is in bit7, which is a bit annoying. -; ;; But we can clock it out with a ROL instruction -; ;; so that it is in C. We can then ROR it into the -; ;; partial data byte. -; ;; We use ROR so that we shift in from the top, so that -; ;; the first bit we shift in ends up in bit 0 after all -; ;; 8 bits have been read. -; ;; ODD: For some reason we don't need to invert the -; ;; received bits. This is weird, because we invert them -; ;; on the way out, and everything in the protocol seems -; ;; to indicate that we sould do so. But experimentation -; ;; has confirmed the bits don't need inversion on reception. + ;; (we do this implicitly below, with a tighter routine, + ;; so that we don't have timing problems, as the requirements + ;; are quite tight. Basically we need to read the clock and data + ;; bit from the same byte read. -; ;; Move data bit into C flag, and loop until bit 6 clears -; ;; i.e., the clock has been released. -;* LDA $DD00 -; ROL -; bpl - + ;; DATA now has the next bit, but inverted (well, except that it turns out not to be). + ;; DATA is in bit 7, which is a bit annoying. + ;; But we can clock it out with a ROL instruction + ;; so that it is in C. We can then ROR it into the + ;; partial data byte. + ;; We use ROR so that we shift in from the top, so that + ;; the first bit we shift in ends up in bit 0 after all + ;; 8 bits have been read. + ;; ODD: For some reason we don't need to invert the + ;; received bits. This is weird, because we invert them + ;; on the way out, and everything in the protocol seems + ;; to indicate that we sould do so. But experimentation + ;; has confirmed the bits don't need inversion on reception. -; ;; Pull it into the data byte -;; pla -; ROR -; pha + ;; Move data bit into C flag, and loop until bit 6 clears + ;; i.e., the clock has been released. +* lda CI2PRA + rol + bpl - -; ;; Wait for CLK to re-assert -; jsr iec_wait_for_clock_assert + ;; Pull it into the data byte + pla + ror + pha -; ;; More bits? -; dex -; bpl iec_rx_bit_loop + ;; Wait for CLK to be pulled again + jsr iec_wait_for_clk_pull -; ;; Then we must within 1000usec acknowledge the frame by -; ;; asserting DATA. At this point, CLK is asserted by the -; ;; talker and DATA by us, i.e., we are ready to receive -; ;; the next byte. (p11). -; jsr iec_assert_data + ;; More bits? + dex + bpl iec_rx_bit_loop -; ;; Retreive the received byte -; PLA + ;; Then we must within 1000 usec acknowledge the frame by + ;; pulling DATA. At this point, CLK is pulled by the + ;; talker and DATA by us, i.e., we are ready to receive + ;; the next byte. (p11). + jsr iec_release_clk_pull_data -; ;; Return no-error -; CLC -; RTS + ;; Retreive the received byte + pla + + ;; Return no-error + clc + rts diff --git a/c64/kernal/iec_turnaround_to_listen.s b/c64/kernal/iec_turnaround_to_listen.s index b65565b7..dcb4f635 100644 --- a/c64/kernal/iec_turnaround_to_listen.s +++ b/c64/kernal/iec_turnaround_to_listen.s @@ -1,39 +1,29 @@ ;; According to http://www.zimmers.net/anonftp/pub/cbm/programming/serial-bus.pdf ;; pages 7--8. - + ;; See also https://www.pagetable.com/?p=1135, https://github.com/mist64/cbmbus_doc + iec_turnaround_to_listen: - ;; Assert data and release clock - lda $dd00 - and #$ef ; release clock (bit 4) - ora #$20 ; assert data (bit 5) - sta $dd00 - - ;; Wait for clock line to be asserted by the drive -* lda $dd00 - and #$40 + ;; Pull DATA, release CLK and ATN (we are not sending commands) + jsr iec_pull_data_release_atn_clock + + ;; Wait for clock line to be pulled by the drive + ldx #$FF ; XXX should we really use that high number? +* + lda CI2PRA + rol ; to put BIT_CI2PRA_CLK_IN as the last (sign) bit + bpl + + dex bne - - ;; http://www.zimmers.net/anonftp/pub/cbm/programming/serial-bus.pdf - ;; page 8 tells us we should not do anything here after waiting for - ;; the clock line to assert. - - ldx #$ff - * lda $dd00 - and #$40 - bne + - dex - bne - + ;; Timeout + jsr printf + .byte "DBG: TURNAROUND FAILED",$0d,$00 + sec + rts - ;; jsr printf - ;; .byte "TURNAROUND FAILED - FILE NOT FOUND?",$0d,$00 - - ;; ;; Timeout = file not found error - ;; ;; (https://www.pagetable.com/?p=1023) - lda #4 - sec - rts -* - ;; ATN turn around successful + ;; CLK is pulled by the device, OK +* clc rts + diff --git a/c64/kernal/iec_tx_command.s b/c64/kernal/iec_tx_command.s index d8f4f795..690fd5a5 100644 --- a/c64/kernal/iec_tx_command.s +++ b/c64/kernal/iec_tx_command.s @@ -35,7 +35,7 @@ iec_tx_command: ;; Common part of iec_txbyte and iec_tx_common - waits for devices ;; and transmits a byte - + pla jsr iec_tx_common diff --git a/c64/kernal/iec_tx_common.s b/c64/kernal/iec_tx_common.s index 05565b80..17a9fcf4 100644 --- a/c64/kernal/iec_tx_common.s +++ b/c64/kernal/iec_tx_common.s @@ -6,11 +6,12 @@ iec_tx_common: ;; Store the bye to send on a stack pha - + ;; Wait till all receivers are ready, they should all release DATA jsr iec_wait_for_data_release - + ;; Pull CLK back to indicate that DATA is not valid, keep it for 60us + ;; We can use this routine as we don't hold DATA anyway (and its state doesn't even matter) ;; Don't wait too long, as 200us or more is considered EOI jsr iec_pull_clk_release_data @@ -42,11 +43,14 @@ iec_tx_common_bit_is_sent: pla dex bpl iec_tx_common_nextbit - + + ;; Whole byte send, make sure ATN is released + jsr iec_release_atn_clk_data + ;; XXX the flow below is REALLY dangerous, as if there are multiple devices, ;; one can signal that it's busy much earlier (more than 100ms) than the other. ;; Can we do something about it? - + ;; All done - give devices time to tell if they are busy by pulling DATA ;; They should do it within 1ms ldx #$FF @@ -62,7 +66,9 @@ iec_tx_common_bit_is_sent: jsr iec_wait100us iec_tx_common_done: + ;; Byte sent, return + clc rts iec_tx_common_nextbit: diff --git a/c64/kernal/iec_tx_eoi.s b/c64/kernal/iec_tx_eoi.s index bb7e3d6d..76169af3 100644 --- a/c64/kernal/iec_tx_eoi.s +++ b/c64/kernal/iec_tx_eoi.s @@ -1,9 +1,10 @@ iec_tx_eoi: - ;; Wait at least 200us + ;; Wait at least 256 usec jsr iec_wait100us jsr iec_wait100us + jsr iec_wait60us ;; Restore the bus to idle state jsr iec_set_idle diff --git a/c64/kernal/iec_wait100us.s b/c64/kernal/iec_wait100us.s index 7ecc57a5..7ccfee98 100644 --- a/c64/kernal/iec_wait100us.s +++ b/c64/kernal/iec_wait100us.s @@ -4,9 +4,9 @@ iec_wait100us: ;; Wait 100usec ;; PAL: - ;; - CPU frequency 0.985248 MHz, we need to waste at least 102 cycles + ;; - CPU frequency 0.985248 MHz, we need to waste at least 99 cycles ;; NTSC: - ;; - CPU frequency 1.022727 MHZ, we need to waste at least 98 cycles + ;; - CPU frequency 1.022727 MHZ, we need to waste at least 103 cycles ;; Waste cycles by reading some unimportant memory location ;; (in a loop) in order not to clutter VICE debug logs diff --git a/c64/kernal/iec_wait20us.s b/c64/kernal/iec_wait20us.s index 1d150264..3ea1349f 100644 --- a/c64/kernal/iec_wait20us.s +++ b/c64/kernal/iec_wait20us.s @@ -4,9 +4,9 @@ iec_wait20us: ;; Wait 20usec ;; PAL: - ;; - CPU frequency 0.985248 MHz, we need to waste at least 21 cycles + ;; - CPU frequency 0.985248 MHz, we need to waste at least 20 cycles ;; NTSC: - ;; - CPU frequency 1.022727 MHZ, we need to waste at least 20 cycles + ;; - CPU frequency 1.022727 MHZ, we need to waste at least 21 cycles ;; Waste cycles by reading some unimportant memory location ;; in order not to clutter VICE debug logs diff --git a/c64/kernal/iec_wait60us.s b/c64/kernal/iec_wait60us.s index 6e77d2b5..0f6cd957 100644 --- a/c64/kernal/iec_wait60us.s +++ b/c64/kernal/iec_wait60us.s @@ -4,9 +4,9 @@ iec_wait60us: ;; Wait 60usec ;; PAL: - ;; - CPU frequency 0.985248 MHz, we need to waste at least 61 cycles + ;; - CPU frequency 0.985248 MHz, we need to waste at least 60 cycles ;; NTSC: - ;; - CPU frequency 1.022727 MHZ, we need to waste at least 59 cycles + ;; - CPU frequency 1.022727 MHZ, we need to waste at least 62 cycles ;; Waste cycles in a loop diff --git a/c64/kernal/iec_wait_for_clk_pull.s b/c64/kernal/iec_wait_for_clk_pull.s new file mode 100644 index 00000000..590903d1 --- /dev/null +++ b/c64/kernal/iec_wait_for_clk_pull.s @@ -0,0 +1,6 @@ + +iec_wait_for_clk_pull: + lda CI2PRA + rol ; to put BIT_CI2PRA_CLK_IN as the last (sign) bit + bmi iec_wait_for_clk_pull + rts diff --git a/c64/kernal/iec_wait_for_clk_release.s b/c64/kernal/iec_wait_for_clk_release.s new file mode 100644 index 00000000..6139dd1d --- /dev/null +++ b/c64/kernal/iec_wait_for_clk_release.s @@ -0,0 +1,6 @@ + +iec_wait_for_clk_release: + lda CI2PRA + and #BIT_CI2PRA_CLK_IN + beq iec_wait_for_clk_release + rts diff --git a/c64/kernal/open.s b/c64/kernal/open.s index 2c043540..a522c778 100644 --- a/c64/kernal/open.s +++ b/c64/kernal/open.s @@ -15,9 +15,6 @@ open: bcs + bmi open_has_space * - jsr printf - .byte "FULL", $0D, 0 - ;; Table is full - according to https://codebase64.org/doku.php?id=base:kernalreference ;; C flag set means error occured sec @@ -74,11 +71,9 @@ open_rs232: open_iec: - ;; XXX add FILENAM support, test it + ;; Part implemented according to https://www.pagetable.com/?p=1031, https://github.com/mist64/cbmbus_doc - ;; Sequence is: - ;; 1. Call current device to attention as LISTENER = $20 + device - ;; 2. + ;; XXX for now for channel 15 only! ;; Disable IRQs, since timing matters! sei @@ -86,14 +81,25 @@ open_iec: ;; Begin sending under attention ;; XXX jsr iec_assert_atn - ;; CLK is now asserted, and we are ready to transmit a byte + ;; Request device to talk lda current_device_number - jsr listen - bcs open_iec_error + jsr talk + bcs open_iec_error ; XXX what about the accumulator? + + jsr printf + .byte "DBG: OPEN 1", $0D, 0 + + ;; Send secondary address + lda current_secondary_address + jsr tksa + bcs open_iec_error ; XXX what about the accumulator? + + jsr printf + .byte "DBG: OPEN 2", $0D, 0 ;; Indicate success lda #$00 - clc + clc open_iec_error: ;; Re-enable interrupts and return diff --git a/c64/kernal/tksa.s b/c64/kernal/tksa.s index 4b599d45..74b2030c 100644 --- a/c64/kernal/tksa.s +++ b/c64/kernal/tksa.s @@ -1,3 +1,12 @@ ; Function defined on pp272-273 of C64 Programmers Reference Guide tksa: + + ;; This routine is documented in 'C64 Programmer's Reference Guide', page 302 and + ;; https://www.pagetable.com/?p=1031, , https://github.com/mist64/cbmbus_doc + ora #$F0 + jsr iec_tx_command + bcs tksa_error + jmp iec_turnaround_to_listen + +tksa_error: rts