Re: Plus/4 6551 receive routine error?

From: Jim Brain <brain_at_jbrain.com>
Date: Sun, 21 Nov 2021 20:59:08 -0600
Message-ID: <03d14f59-0551-8be5-54a7-b14eaae3ea48_at_jbrain.com>
Response from USENET:


Jim Brain says...

  > It might make sense to write up a bit more of the
  > disassembly with your notes to create clarity.

See below.

  > Ah, that clears things up for me.  So, if $34 $00 were
  > the data items, the data delivered to the +4 app would
  > be $34 $34

Yes, that's right.  I think regular BBS traffic probably
wouldn't have any nulls, so for that, this problem wouldn't
make any difference.  But I think file transfers might have
lots of nulls, including any two-byte block numbers, or
two-byte checksums. And of course any program with an ML
section would have nulls all over the place (LDA #$00, STA
$FD00, and such).

Below is the relevant section of somebody's kernel source
code, and on the right side the more raw version of the same
thing showing the actual hex values.

The error results from an attempt to work software flow
control (Xon/Xoff) into the ACIA IRQ servicing routines.  If
flow control is enabled, the values normally used for Xon
and Xoff ($11 and $13 respectively) will be stored at
locations $FC and $FD.  If flow control is disabled, those
locations will contain nulls.

If flow control is disabled, a received null byte must not
be compared to $FC or $FD because a false match would be
detected, and we would be halting and resuming transmission
for no reason.  So the code branches around all the Xon/Xoff
stuff if a null is received.  But it fails to save the null
in aintmp ($07D5) before branching.  So later, when the
value in aintmp is retrieved and added to the input queue,
another copy of the last non-null byte received is what will
go into the queue.

The solution is to reverse the two instructions, so the null
is saved into aintmp, then the BEQ is performed.  The Zero
flag will not be modified by the STA instruction, so the
branch will work correctly.

ain
        lda  astat       ; acia status reg prev. saved    LEA95   LDA   $07D4
        and  #$8         ; bit 3 set if char recd.                AND   #$08
        beq  rxfull      ; no char has been received              BEQ   LEAF0
        lda  astat       ; got one...reset stat bit               LDA   $07D4
        and  #$f7                                                 AND   #$F7
        sta  astat                                                STA   $07D4
        lda  acia        ; read byte                              LDA   $FD00
        beq  notacc      ; if null, skip xon/xoff                 BEQ   LEAC2

; it's a null, don't let thru for x-disable

        sta  aintmp      ; save char [unless it was a null]       STA   $07D5
        cmp  xon         ; is it a ~q                             CMP   $FC
        bne  trycs       ; nope                                   BNE   LEAB7

; got a ~q

        lda  #0                                                   LDA   #$00
        sta  alstop      ; tell local xmit to go                  STA   $07D6
        beq  rxfull      ; !bra, what character?                  BEQ   LEAF0

trycs
        cmp  xoff        ; is it a ~s                     LEAB7   CMP   $FD
        bne  notacc      ; nope                                   BNE   LEAC2

; got a ~s

        lda  #$ff                                                 LDA   #$FF
        sta  alstop      ; tell local xmit to stop                STA   $07D6
        bne  rxfull      ; !bra, i didn't see that...             BNE   LEAF0

notacc
        lda  inqcnt                                       LEAC2   LDA   $07D3
        cmp  #inpqln-1   ; is queue full                          CMP   #$3F
        beq  rxfull      ; yep                                    BEQ   LEAF0
        cmp  #hiwatr     ; high water mark                        CMP   #$38
        bne  nohw        ; nope                                   BNE   LEADC

; hit high water mark, tell sender to stop

        lda  xoff        ; x-sw is off                            LDA   $FD
        beq  nohw                                                 BEQ   LEADC
        sta  soutq       ; ~s                                     STA   $07CF
        lda  #$ff                                                 LDA   #$FF
        sta  soutfg      ; flag it present                        STA   $07D0
        sta  arstop      ; flag remote stopped                    STA   $07D7

nohw
                         ; not full, insert char
        ldx  inqfpt      ; do: inqfpt <- inqfpt+1 mod 64  LEADC   LDX   $07D1
        inx                                                       INX
        txa                                                       TXA
        and  #$3f                                                 AND   #$3F
        sta  inqfpt                                               STA   $07D1
        tax                                                       TAX
        lda  aintmp      ; get char to insert                     LDA   $07D5
        sta  inpque,x    ; insert it                              STA $03F7,x
        inc  inqcnt      ; another drop in the bucket             INC   $07D3
rxfull                  ; error exit
        rts              ; all ok                         LEAF0   RTS
Received on 2021-11-22 05:00:08

Archive generated by hypermail 2.3.0.