Codebase64 on the Kernal behaviour

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
        JSR $FFAB     ; call UNTLK
        ... device not present handling ...

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 */
if (st)

iec_send_talk(device_number, &st);
iec_send_secondary_address_after_talk(CTRL_CODE_DATA | CHANNEL_CMD, &st);
iec_read(buff, szBuff, &bytesRead, &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.

About Luigi Di Fraia

I am a Senior DevOps Engineer so I get to work with the latest technologies and open-source software. However, in my private time I enjoy retro-computing.
This entry was posted in Retrocomputing, Technical and tagged , , , . Bookmark the permalink.

1 Response to Codebase64 on the Kernal behaviour

  1. Pingback: An unexpected fix to the Commodore Kernal | Luigi Di Fraia's e-Footsteps

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s