lgblgblgb / xemu

Emulations (running on Linux/Unix/Windows/macOS, utilizing SDL2) of some - mainly - 8 bit machines, including the Commodore LCD, Commodore 65, and the MEGA65 as well.
https://github.com/lgblgblgb/xemu/wiki
GNU General Public License v2.0
208 stars 32 forks source link

MEGA65: $d610 key detection not working #311

Closed smnjameson closed 3 years ago

smnjameson commented 3 years ago

Using the SID player from https://files.mega65.org?id=5ce1c3cf-8a83-491a-8201-89b06137b0a6 You are unable to select any other song using the keyboard as you can on real HW, until you enable and then disable the mousegrab options in the input menu.

The player uses $d610 to read the ASCII key value

lgblgblgb commented 3 years ago

Thanks for reporting. Xemu does emulate this feature. So I suspect something other in the background.

Hardware accelerated keyboard scanner

$D610 maintains a "queue" of pressed chars in the past, to be more precise (AFAIK ...) a 4 bytes long buffer. Reading $D610 will provide the last char (ASCII value) in the buffer (or zero, if there is no character) without removing the character though. To remove the top-most item, a write should be performed on $D610 (the actual written value does not count, just the fact of writing something).

My theory about the problem

As far as I can imagine, the player does not remove the read character from the queue in some cases, like when it's not the desired ASCII values of keys 1,2,3,4,5 to select a song. Since the (emulated) machine was used before, the $D610 buffer already contains some character, which probably not the expected keys 1-5 values. The player seeing not the right keys pressed, may forget to remove the character, so it never gets the new ones.

The "mouse grab trick" works as a workaround for different reasons, not related to this issue too much: since Xemu maintains at least two ways to detect keypresses (during the emulation, and using any GUI primitives, like warning box about mouse grab displayed), it has to reset the input pending events to avoid "leaking" key events to one subsystem to another (ie, when user just press enter to dismiss the warning box instead of clicking, when that enter would "leak" as a RETURN in the emulated machine as well then ...). So the sole reason it seems to help, is because the reset even queue.

Best practices with $D610

  1. $D610 really should be written (with any value) unconditionally after read, to remove the read character and to avoid an issue like this (ok, maybe unless if it's zero, when there is no character in the buffer - in this only case, it's even dangerous to write since there can be a race condition to remove a char from buffer just arrived after the read).

  2. Also, when starting a program using $D610, it should empty the queue first, to avoid older pressed (and maybe never read out) characters there to interfere with your program. Since probably before the start of the program, ROM was used to type LOAD (etc ...) and the ROM does not bother (AFAIK) with $D610, so there are still keypresses there left for the time when your program start running. The important point: normal keyboard matrix scan and this $D610 feature are independent, no char will be removed from the $D610's used queue, just because you get your keypress in another way (ie with scanning the keyboard matrix, what the ROM does).

  3. Do not assume keyboard buffer is empty (ie, the previous point). Here there can be differences: MEGA65 is often used with remote control thus no keyboard press. With Xemu, even the -prg option etc, uses simulated keypresses. This is not a bug, and would affect (IMHO ...) the MEGA65 as well, if somebody types something to LOAD the program for example, instead of using "remote control" to load the program.

I'm not sure if these points worth to be mentioned in the manual as well, as possible "traps" ...

For me, it's kinda natural, as with writing the emulator, I was thinking a lot, how it should work and what about these possible traps. But it's maybe not the same for someone want to use this feature without too much attention about the details before.

The suspected reason

what likely happened: on MEGA65 the program was run with "remote control" (ie monitor or something) and no keypresses happened before, thus the problem hasn't been triggered there yet.

Testing my theory

The theory is only a theory till it's tested. :) So it should be tested on MEGA65, if the problem is there as well, if there was any keypress before starting the program.

smnjameson commented 3 years ago

The problem is the discrepancy between HW and Xemu without writing to it

Real HW refreshes on key press, but Xemu not.

On Xemu

On Real HW

So it would seem writing to $d610 only has the effect of assisting you with acknowledging you have read the ASCII value, to prevent some code running twice or more per key press.

Could just be a misinterpretation of the manual: "Write to clear event ready for next", which I guess should be clarified in the documentation.

lgblgblgb commented 3 years ago

Seems to be some issue in mega65-core as well, see: https://github.com/MEGA65/mega65-core/issues/465

We should wait, what the final verdict about the hardware now, to really know what should be emulated ;)

lgblgblgb commented 3 years ago

I close this issue now in favour of #148 . That's a long pending issue to correctly emulate the buffer-length. Now it's the question what it should be and how exactly it should behave, so I think, it's really up to that issue to be solved and closed after the solution!