I found out that codebase64 mentions the issue I reported about reading the error channel/status info from devices that are not on the IEC bus. The author of the article refers to the issue as a deadlock.
An interesting thing I found out back when I was writing the “serial-device” API in IECHost (the API that sits on top of the TALK/LISTEN API) is that in the following snippet of code (presented at the bottom of the above mentioned page on codebase64) the LISTEN/UNLISTEN part is absolutely vital when the code runs on a Commodore 64:
LDA #$00 STA $90 ; clear STATUS flags LDA $BA ; device number JSR $FFB1 ; call LISTEN LDA #$6F ; secondary address 15 (command channel) JSR $FF93 ; call SECLSN (SECOND) JSR $FFAE ; call UNLSN LDA $90 ; get STATUS flags BNE .devnp ; device not present LDA $BA ; device number JSR $FFB4 ; call TALK LDA #$6F ; secondary address 15 (error channel) JSR $FF96 ; call SECTLK (TKSA) .loop LDA $90 ; get STATUS flags BNE .eof ; either EOF or error JSR $FFA5 ; call IECIN (get byte from IEC bus) JSR $FFD2 ; call CHROUT (print byte to screen) JMP .loop ; next byte .eof JSR $FFAB ; call UNTLK RTS .devnp ... device not present handling ... RTS
In fact, the LISTEN/UNLISTEN block serves an important purpose: the earliest time a “device not present” condition can be detected is after the secondary address is sent (after LISTEN). In other words, when the request to send LISTEN is made, the Kernal does not signal the “device not present” condition to the code that made the request.
A TALK/UNTALK block is unsuitable for detecting if a device is present because after the secondary address (after TALK) is sent, the bus turnaround process is initiated as well, which is where the code hangs 🙂
The equivalent code using IECHost’s LISTEN/TALK API directly (which is essentially knowing which commands to send using IEC bus routines) is:
st = 0; /* Clear status flags */ iec_send_listen(device_number, &st); iec_send_secondary_address_after_listen(CTRL_CODE_DATA | CHANNEL_CMD, &st); _delay_us(20); /* Some delay is mandatory before sending UNLISTEN */ iec_send_unlisten(&st); if (st) return IOERR_DEVICE_NOT_PRESENT; iec_send_talk(device_number, &st); iec_send_secondary_address_after_talk(CTRL_CODE_DATA | CHANNEL_CMD, &st); iec_read(buff, szBuff, &bytesRead, &st); iec_send_untalk(&st);
Another interesting thing is that the file abstraction (OPEN/CLOSE) cannot be used for the same purpose. The reason is that a command such as the one below:
OPEN 15,8,15
does not actually cause any communication to device 8. It only sets up the file table on the host computer.
One might be tempted to try the below command instead, in order to send LISTEN/secondary address after LISTEN/UNLISTEN to a device and then check ST ($90) to detect if the device is present or not:
OPEN 15,8,15,""
Unfortunately for us, the host computer still won’t initiate any IEC communication at all as it understands that the length of the parameter is 0 so there’s no need to go through the LISTEN/secondary address after LISTEN/UNLISTEN sending process.
Pingback: An unexpected fix to the Commodore Kernal | Luigi Di Fraia's e-Footsteps