z88dk / z88dk

The development kit for over a hundred z80 family machines - c compiler, assembler, linker, libraries.
https://www.z88dk.org
Other
914 stars 174 forks source link

new c lib, sccz80, zx target: JOYFUNC not working #1103

Closed thefossilrecord closed 5 years ago

thefossilrecord commented 5 years ago

Compiling with latest version of sccz80 on Linux (14110-9df52a2-20190208), code for ZX Spectrum using the joystick functionality stops working.

#include <input.h>

char keys[]="qaop ";
udk_t k;
JOYFUNC joystick;

int main()
    {
    unsigned char *screen = 22528;
    unsigned char direction = 0;
    k.up  = in_key_scancode(keys[0]);   // defaults to 'q';
    k.down = in_key_scancode(keys[1]);  // defaults to 'a';
    k.left = in_key_scancode(keys[2]);  // defaults to 'o';
    k.right = in_key_scancode(keys[3]); // defaults to 'p';
    k.fire = in_key_scancode(keys[4]);  // defaults to 'space';

    joystick = (JOYFUNC)in_stick_keyboard;

    while(1)
        {
        direction = (joystick)(&k);
        if(direction)
            *screen = (direction - 1) * 8;
        }

    return 0;
    }

Compiling generates the following:

zcc +zx -vn -startup=31 -clib=new joyfunc.c

sccz80:"joyfunc.c" L:21 Warning:Calling via non-function pointer [-Wincompatible-pointer-types]
sccz80:"joyfunc.c" L:21 Warning:Assigning from a void expression [-Wvoid]

Running the code, the coloured block doesn't change when you press q,a,o,p. Code compiles without warnings and runs as expected with zsdcc ( 3.8.5 #10892).

Header file input_zx.h does the following which may be related as it seems SCCZ80 is special cased:

#ifdef __CLANG
typedef uint16_t (*JOYFUNC)(udk_t *);
#endif

#ifdef __SDCC
typedef uint16_t (*JOYFUNC)(udk_t *);
#endif

#ifdef __SCCZ80
#define JOYFUNC  void*
#endif
suborb commented 5 years ago

That is a problem with the header and sorting out removes the warnings but not the bug.

The underlying issue is that the in_stick_keyboard is marked as fastcall in the headers only for sccz80. This is problematic since it’s being called via a function pointer which trashes hl.

I can try to take a look, but newlib isn’t my speciality.

thefossilrecord commented 5 years ago

Thanks for looking. Oddly enough, in the older version of z88dk where it was working before, in_stick_keyboard is declared as

extern uint16_t __LIB__ __FASTCALL__ in_stick_keyboard(udk_t *u) __smallc;

in input_zx.h, so it looks like its always been fastcall. The z80 assembly for the function (asm_in_stick_keyboard.asm) between the two versions of z88dk I have appears to be identical so it's odd that it's no longer working.

suborb commented 5 years ago

I've gone back to 20170101 and I can see the behaviour you're reported. Back then a function pointer call was this:

        ld      hl,(_joystick)
        push    hl
        ld      hl,_k
        pop     de
        ld      bc,i_6
        push    hl
        push    bc
        push    de
        ld      a,1
        ret

and now it's like this:

        push    hl
        ld      hl,(_joystick)
        push    hl
        ld      hl,_k
        ex      (sp),hl
        call    l_jphl

In the old version, you can see that hl is preserved.

The sequence changed in 9f6a1377d41422c2a3d1c1cd90bce146d2ea1510 back in October 2017.

It looks like there's a general problem with newlib and sccz80 - all single parameter functions are marked as fastcall without doing the macro switch that sdcc does. This means that taking the function pointer for any of those functions will break in the same way.

I think I'll leave the larger issue for @aralbrec to sort out, but I think I can fix the behaviour in this particular case with a small compiler tweak and a header change.

thefossilrecord commented 5 years ago

This is marked as closed but I've just downloaded and compiled the latest z88dk source (May 6th) on a new install of Ubuntu Mate 18.02 and I'm still seeing broken behaviour with JOYFUNC when compiling the above example with sccz80. Am I missing something?

suborb commented 5 years ago

Sorry, it looks like I was off by a word or so on the stack equalisation - for some reason my test program was working yet yours wasn't.

Fingers crossed I've sorted it finally.

thefossilrecord commented 5 years ago

I've checked the test program and with one of my own projects that uses JOYFUNC under sccz80 and it's now working as expected. Thank you for looking into this again.

suborb commented 5 years ago

No worries. Apologies for mucking up the first fix! Glad it’s all sorted now though.