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