Reproducing the 6522 shift register bug

From: Dave McMurtrie <cbm-hackers_at_commodore.international>
Date: Sat, 23 Dec 2023 18:00:54 -0500
Message-Id: <9bab45fa-caf0-41f5-a240-7a4c9e552510_at_app.fastmail.com>
Hi cbm-hackers,

I'm trying to reproduce the 6522 VIA shift register bug for demonstration purposes. I'm doing so with two Commodore VIC-20 computers connected at the user port via CB1, CB2 and PB0. CB1 and CB2 are used for data and clock, and PB0 is used as a busy indicator by the receiver to tell the sender when it's ready to receive another byte.

I wrote simple sender and receiver code. The sender just sends the ASCII bytes A through Z. The receiver receives those bytes and outputs them to the screen. The sender is using mode 110 (shift out at system clock rate). The receiver is using mode 011 (shift in under control of external input pulses) which is supposed to be the buggy mode.

The good news is that the data that is output by the receiver isn't always correct. So either I am successfully demonstrating the 6522 shift register bug or I'm just misunderstanding how to use the 6522 properly and my code is wrong.

The sender is:

START          LDY #$41 ; Char to send. start with ascii 'A'
               LDX #$7F
               STX IER2 ; disable IRQ
               LDX #$00
               STX PCR1
               STX ACR1
               STX DDRB1 ; PB0 is an input
LOOP           LDX #%00011000 ; SR mode 110 (bits 2-4) shift out under control
                              ; of system clock
               STX ACR1
BUSY           LDA PB
               AND #%00000001 ; if PB0 is high, the receiver is busy
               BNE BUSY
               STY SR1  ; store the char to send in the shift register
               INY
               CPY #$5B ; if we're beyond ascii Z, reset back to A
               BNE WAIT
               LDY #$41
               BRK ; break instead of looping to only send A-Z once
WAIT           SEI
               LDA IFR1 ; load the Interrupt Flag Register
               AND #$04 ; check to see if the SR bit is set
               BEQ WAIT ; if not, wait.
               LDX #$00
               STX IFR1 ; clear the interrupt flag
               CLI
               JMP LOOP 

The receiving code is:

START          LDX #$7F
               STX IER2 ; disable IRQ
               LDX #$00
               STX PCR1
               LDX #%00000001 ; set PB0 as an output
               STX DDRB1
LOOP           LDX #%00001110 ; SR mode 011 (shift in under control of
                              ;              external clock pulses)
                              ;              (bits 2-4)
                              ; latching on PB is enabled via bit 1
               STX ACR1
WAIT           SEI
               LDX #$00
               STX PB ; pull PB0 low to indicate ready
               LDA IFR1 ; load interrupt flag register
               AND #%00010000 ; check if CB1 interrupt bit is set
               BEQ WAIT ; if not, WAIT
               LDX #$01
               STX PB  ; release PB0 high to indicate busy
               LDA SR1
               CLI
               JSR $FFD2
               LDX #$00
               STA IFR1
               JMP LOOP

The only documentation I found on how this should work was the MOS6522 data sheet and that was a bit like trying to read the blueprints for a minotaur's home. Let me know if I'm doing something completely wrong here.

Thanks!

Dave
Received on 2023-12-24 01:00:02

Archive generated by hypermail 2.3.0.