Weird Joystick behaviour

All aspects of programming on the Commander X16.
ch4rl3sb
Posts: 42
Joined: Fri May 12, 2023 10:22 am

Weird Joystick behaviour

Post by ch4rl3sb »

Can anyone explain this behaviour?
My previous version used an asm file that was merged into my C code. Since I needed to rewrite my linked list procedures, I thought I would try to do the asm functions inline in C rather than exporting from a separate asm file. But, I'm not very conversant with the syntax.
Anyway, I had a similar quirk in both versions:
If you see, I have to call Read_Joystick() an extra time. If I don't, the first read doesn't process.
This caused me no end of frustration in both versions when I was trying to get the joystick working initially,
since my initial tests called the joystick only once for the joystick I was trying to test and get working, (either
0 for keyboard, or 1 or 2 for physical sticks.)
Calling it only once for any joystick reads nothing.
Calling multiple, the first joystick called doesn't register. No matter what order I put them in, the first one is the
one that doesn't work.

Also, if I turn on the mouse first, a single joystick call works.
(I included a mouse test near the end of read_joystick just so I could shut down the program when joystick
wasn't working.)

Code: Select all

/*****************Main Program Start*********************************/
void main(void){
  Init_IRQ();
  x = 0; y = 0; z = 0;
  counter1 = 0; counter2 = 0; counter3 = 0;
  Init_Memory_A();

  keys = 0;
  while (keys == 0){

    while (vsync_set == 0){
      counter2++;
    }
    vsync_set = 0;
    counter1++;
    Read_Joystick(0);
    Read_Joystick(0);
    Read_Joystick(1);
    Read_Joystick(2);
  }
  Restore_IRQ();
}

void Read_Joystick(unsigned char stick){
  temp = stick;
  
  __asm__ ("lda %v",temp); // load a with joystick #
  __asm__ ("jsr %w",JOYSTICK_GET);

  __asm__ ("sta %v",joy_keys0);
  __asm__ ("stx %v",joy_keys1);
  __asm__ ("sty %v",joy_present);

  if (joy_present != 0xFF){
    if ((joy_keys0 & 0x20) == 0){keys = 1;}
    //if (joy_keys0 != 0xFF){keys = 1;}
  }

  //mouse test
  __asm__ ("ldx #$22");
  __asm__ ("jsr %w",MOUSE_GET);
  __asm__ ("sta %v",temp);
  if ((temp & 1) == 1){keys = 1;}
}
/*****************End Main Program********************************/
DragWx
Posts: 340
Joined: Tue Mar 07, 2023 9:07 pm

Re: Weird Joystick behaviour

Post by DragWx »

Hmm... what is your JOYSTICK_GET constant set to?

Edit: I'm at a loss because all joystick_get does is read three memory locations and returns them in A, X, and Y.

There's only two ways I can think of for two consecutive calls to read the same three memory locations to return two different results:
1) if joystick_scan is called right in between the two calls (like if the vblank irq is happening, which it probably isn't because you're specifically waiting for it first)
2) if the current RAM bank isn't set correctly, which is strange because the very first thing joystick_get does is set the RAM bank to 0, unless you're somehow not calling the beginning of the routine.
ch4rl3sb
Posts: 42
Joined: Fri May 12, 2023 10:22 am

Re: Weird Joystick behaviour

Post by ch4rl3sb »

JOYSTICK_GET is 0xFF56. Just like it specifies in the KERNAL docs.
And, yes, I wait for the V-blank.

So, this took me several days to get the joystick working, wondering what I was doing wrong with my new inline asm code.
And forgetting that a few months back I had a similar few days trying to get them working in the original program.
DragWx
Posts: 340
Joined: Tue Mar 07, 2023 9:07 pm

Re: Weird Joystick behaviour

Post by DragWx »

I've mocked up a simple program, but I cannot reproduce your issue, so the problem might be somewhere else in the program. Here, take a look:

main.c

Code: Select all

#include <cx16.h>
#include <conio.h>

#define JOYSTICK_GET 0xFF56

// From irq.s
extern unsigned char VBlankCnt;

static unsigned char temp, count, joyA, joyB, joyC;

void Read_Joystick(unsigned char stick){
    temp = stick;
  
    __asm__ ("lda %v", temp); // load a with joystick #
    __asm__ ("jsr %w", JOYSTICK_GET);

    __asm__ ("sta %v", joyA);
    __asm__ ("stx %v", joyB);
    __asm__ ("sty %v", joyC);
}

void main(void) {
    unsigned char running = 1;

    // Initialize all static variables.
    temp = count = joyA = joyB = joyC = 0;

    clrscr();
    cprintf("Please release any buttons...\r\n");
    while (count < 60) {
        VBlankCnt = 0;
        while (!VBlankCnt) { }
        count++;
    }
    cprintf("Now running! Press the START button on your joystick or keyboard.\r\n");

    count = 0;
    while (running) {
        // Wait for vblank.
        VBlankCnt = 0;
        while (!VBlankCnt) { }

        // Count vblanks so we can output a '.' every second to show that the
        // program is still running.
        count++;
        if (count >= 60) {
            cprintf(".");
            count = 0;
        }

        // Read joysticks.
        Read_Joystick(0);
        if (joyC != 0xFF) {
            if ((joyA & 0x10) == 0) {
                cprintf("\r\nSTART has been pressed!\r\n");
                running = 0;
            }
        }
    }
    cprintf("Now exiting.\r\n");
}
irq.s

Code: Select all

.export _VBlankCnt
.interruptor IRQ_Handler

.bss
_VBlankCnt:  .res 1

.code
IRQ_Handler:
    LDA $9F27
    AND #$01
    BEQ IRQ_Handler_Exit
    INC _VBlankCnt
IRQ_Handler_Exit:
    RTS
to build: cl65 -t cx16 -o JOY.PRG main.c irq.s

When I run this in the emulator, it works exactly as expected, and I'm only using a single call to read the joystick.
cx16-joystick.png
cx16-joystick.png (8.69 KiB) Viewed 4648 times
ch4rl3sb
Posts: 42
Joined: Fri May 12, 2023 10:22 am

Re: Weird Joystick behaviour

Post by ch4rl3sb »

When I run this, it exits on ENTER, (keyboard joystick <start> button.)
but there is no text. none of the printf functions print anything visible. it leaves blank space as if it did.

Also, I have some questions because I don't understand your irq.s file
the compiler may create .s files, but I have never used one myself.

how does your irq handler install itself?

".bss
_VBlankCnt: .res 1"
is obviously where VBlankCnt is stored, but what do [.bss], and [.res 1] mean?
how does that set aside a byte for VBlankCnt? (I know that VBlankCnt: is the asm label)

also, this doesn't seem to reset $9f27, (vera isr).
wouldn't it be 1 every time the handler is called after the first vertical blank?
wouldn't this assume every interrupt is a vblank? (I can't test that as my screen is blank, but
wouldn't every other interrupt also trigger this? like mashing the keyboard could cause [.] to print
faster than 1 per second.)
DragWx
Posts: 340
Joined: Tue Mar 07, 2023 9:07 pm

Re: Weird Joystick behaviour

Post by DragWx »

Hmm... you might need to update your copy of CC65; the one I'm using is one I grabbed from github just a few weeks ago: CC65 Github, click the "actions" tab, "snapshot build", and pick one of those.

I've attached the PRG file I get when I build this code, and I can confirm that this works when I run it in the emulator.



".S" files are for when you want to write in assembly. I don't think CC65 compiles .C files to .S files, I think they go straight to .O files, like .S files do when you run CA65 on them.

According to the CX16-specific information from the CC65 documentation, if you're compiling a C program for the CX16, all you have to do is export an assembly routine using the .interruptor directive instead of the .export directive, and CC65's standard library will handle installing it for you when the program runs. I don't know if there's a way to export a C function like this though, and there's no automatic install if you're writing an assembly-only program. :P

.bss is shorthand for .segment "BSS".
BSS is the chunk of memory where all uninitialized variables go. (I don't know why it's called "BSS", only that that's what it's used for)
_VBlankCnt: .res 1 means "set _VBlankCnt to the next available memory address in the current segment (BSS), and reserve 1 byte for me to use there". With .res 2 instead, I'd have _VBlankCnt and _VBlankCnt+1 to work with, and I could tell C that this is an unsigned short instead, or possibly an array of unsigned chars of size 2.

Why BSS? Because for this code, I was going to manually set the variable to 0 just before using it, so I don't need the compiler to worry about setting it to anything when it goes to load the program. (It's one less byte it has to to read from disk and copy to memory, in other words)
For comparison, the DATA segment is where you can put variables that you want the C library to automatically initialize for you. You'd do something like MyVar: .byte $10 there instead, which literally means, "just plop a $10 byte here and give MyVar the address of it". But again, just like .interruptor, this isn't automatic if you're writing an assembly-only program.

As for $9F27, CC65 doesn't replace the kernal's default IRQ handler, so I'm relying on the fact that the kernal will deal with acknowledging the VERA's IRQs for me. I could've acknowledged it in my handler, but that might cause problems for other handlers that might run after mine, which I might not know about. I can confirm that all of the vblank-related delays I put in were working correctly when I ran it.
Attachments
JOY.PRG
(2.58 KiB) Downloaded 260 times
ch4rl3sb
Posts: 42
Joined: Fri May 12, 2023 10:22 am

Re: Weird Joystick behaviour

Post by ch4rl3sb »

DragWx wrote: Sat Jun 17, 2023 4:48 am Hmm... you might need to update your copy of CC65;
Maybe.
".S" files are for when you want to write in assembly.
ah. I was using .asm file.
.bss is shorthand for .segment "BSS".
BSS is the chunk of memory where all uninitialized variables go.
.res 1
had never seen .res for reserve...
I was always doing things like:
MyVar: .byte $10,$A0,$05
etc..
DragWx
Posts: 340
Joined: Tue Mar 07, 2023 9:07 pm

Re: Weird Joystick behaviour

Post by DragWx »

I normally use .asm too (I used the DASM assembler right up until the CX16), and it was actually CA65 where I learned that .s is also a common extension for source code written in assembly, which seems to be a convention from the GNU compiler collection.

and yeah, when you're in the BSS segment, you just have to know that you use ".res", since the BSS segment cannot have any data physically put into it, only address reservations.
ch4rl3sb
Posts: 42
Joined: Fri May 12, 2023 10:22 am

Re: Weird Joystick behaviour

Post by ch4rl3sb »

Yes, of course I was mistaken, the compiler creates .o files, not .s
That's what I was thinking of.
As for $9F27, CC65 doesn't replace the kernal's default IRQ handler,
I still don't understand how that installs things well enough to use it. (other than to copy the exact code.)
How would you install a keyboard handler?

I've been using the interrupts at 0x0314 for checking VSYNC
And the keyboard vector is at 0x032E
ch4rl3sb
Posts: 42
Joined: Fri May 12, 2023 10:22 am

Re: Weird Joystick behaviour

Post by ch4rl3sb »

DragWx wrote: Sat Jun 17, 2023 4:48 am the one I'm using is one I grabbed from github just a few weeks ago: CC65 Github, click the "actions" tab, "snapshot build", and pick one of those.
Am I going to have to install and setup a new development framework? and which one and why?
I'm currently using Cygwin, which I don't understand much. It has a CC65 thing built in. ca65, cl65, cc65 etc.
none of which I understand much. It doesn't look like I could just drop the new cc65 in there.
I really need a compiler setup that just works in the background and doesn't need me to spend days figuring out
how to set it up.

I keep having these frutrating periods where I'm not able to code the game because I'm trying to get other stuff to work.
Switching to R43, why doesn't sound work with the example code given, why doesn't the joystick access with the given function, how to use github to backup code, (which I still havent' figured out,) converting text from string literals like Text = "Hello World!" or keyboard input to something that will actually print in the different tileset used in VERA, etc. Each taking days of frustration that leaves me not even wanting to work on my game.
Post Reply