Search code examples
assemblyz80

Z80 function called by Joystick button prints extra strings instead of the expected one


While exploring joystick connection to the Z80 games I've got this code, which should print 1 letter when I press Up, Left or Right. But for some reason when I press Left it prints lru, when I press Right it prints ru, and u after pressing Up.

            org 32768

    loop    ld bc,31        ; Kempston joystick port.

            in a,(c)        ; read input.
            and 2           ; check "left" bit.
            call nz,joyl    ; move left.
            in a,(c)        ; read input.
            and 1           ; test "right" bit.
            call nz,joyr    ; move right.
            in a,(c)        ; read input.
            and 8           ; check "up" bit.
            call nz,joyu    ; move up.
            in a,(c)        ; read input.
            and 4           ; check "down" bit.

            halt
            jp loop

    joyl    ld de,sl        ; address of string
            ld bc,eostrl-sl ; length of string to print
            call 8252
            ret

    joyr    ld de,sr
            ld bc,eostrr-sr
            call 8252
            ret

    joyu    ld de,su
            ld bc,eostru-su
            call 8252
            ret

    sl      defb "l"
    eostrl  equ $
    sr      defb "r"
    eostrr  equ $
    su      defb "u"
    eostru  equ $

Three different "variables" with unique string length labels, but why calling joyl prints all three letters instead of one?


Solution

  • The subroutines change the value of the BC register so if one of them is called the subsequent IN A,(C) instructions will read the wrong port.

    Put a LD BC,31 before every IN A,(C) to fix this. Or you could save and restore BC in the subroutines with a push and pop like so:

    joyu    push bc
            ld de,su
            ld bc,eostru-su
            call 8252
            pop bc
            ret