[Research] Find out why ≥TH03 checks input twice per frame, with a 0.6ms delay

Thanks to @joncampbell123 for the tip!

Funded by zorg.
This commit is contained in:
nmlgc 2018-09-13 18:32:24 +02:00
parent cbe8a37c53
commit 8dfc2cd535
6 changed files with 132 additions and 0 deletions

4
.gitignore vendored
View File

@ -2,3 +2,7 @@ bin/th*
bin/TH*
bin/zuncom
bin/ZUNCOM
Research/*.exe
Research/*.obj
RESEARCH/*.EXE
RESEARCH/*.OBJ

97
Research/HOLDKEY.C Normal file
View File

@ -0,0 +1,97 @@
/* ReC98 Research
* --------------
* PC-98 keyboard key hold behavior test
*/
#pragma option -ms
#include "../libs/master.lib/master.h"
#if defined(__TURBOC__) && defined(__MSDOS__)
// Remove C++ exception handler bloat on Borland compilers
// (see https://community.embarcadero.com/article/technical-articles/162/14700)
void _ExceptInit(void)
{
}
#endif
// Should cover the number of possible input states within a frame
// ⌈(19200 baud / 11 bit) / 56.4 fps⌉ ≈ 31, but let's rather be extra safe...
#define STATES_MAX 64
void hr(int len)
{
int i;
dos_puts("\r\n");
for(i = 0; i < len; i++) {
dos_puts("\x86\x44");
}
dos_puts("\r\n");
}
void frame(void)
{
char states[STATES_MAX];
char state_prev = 0;
unsigned int states_recorded = 0;
unsigned int i = 0;
int flipped = 0;
vsync_Count1 = 0;
do {
int delayloop = 1024;
unsigned char input = *(volatile unsigned char far*)(0x531);
states[states_recorded++] = (input >> 2) & 0xF;
while(delayloop && vsync_Count1 < 1) {
_asm out 0x5F, AL;
delayloop--;
}
} while(vsync_Count1 < 1);
dos_puts("\r \r");
for(i = 0; i < states_recorded; i++) {
char state = states[i];
if(state_prev != state && i > 0) {
flipped++;
dos_puts("\x1B[17m");
} else {
dos_puts("\x1B[0m");
}
dos_putch((state < 10) ? ('0' + state) : ('A' - 10 + state));
dos_putch(' ');
state_prev = state;
}
if(flipped >= 2) {
dos_puts("\r\n");
}
}
void main(void)
{
vsync_start();
hr(79);
dos_puts(
"Hold any of the cursor keys. The line below will show all states of the cursor\r\n"
"keys, read using the keyboard state memory bitmap at 0x52A (which is also how\r\n"
"TH02 and later read input), within a single frame.\r\n"
"The 0.6ms delay between the states roughly matches the keyboard UART delay.\r\n"
"\r\n"
"After the typematic delay, you might see the occasional wrong state popping up.\r\n"
"This will be highlighted in\x1B[17m red \x1B[0mand kept on screen when it happens.\r\n"
"Unlike on IBM PC/XT/AT where holding a key repeats only the down scancode,\r\r\n"
"PC-98 keyboards repeat up AND down scancodes, leading to these state flips.\r\n"
"So, polling the keyboard twice within a frame, ~0.6ms apart, is indeed a good\r\n"
"idea for a game engine, which is why ZUN chose to do it from TH03 onwards.\r\n"
"\r\n"
"Hold Q to quit."
);
hr(79);
while(!(*(volatile char far*)(0x52C) & 0x01)) {
frame();
}
hr(79);
vsync_end();
}

12
Research/Makefile.mak Normal file
View File

@ -0,0 +1,12 @@
# ReC98 Research
# --------------
# Makefile
.autodepend
LFLAGS = -L..\bin\
all: HOLDKEY.EXE
HOLDKEY.EXE: HOLDKEY.OBJ
$(CC) $(LFLAGS) masters.lib $**

6
Research/README.md Normal file
View File

@ -0,0 +1,6 @@
This directory collects various pieces of research into PC-98 hardware details
that were made during the reverse-engineering phase, in order for us to better
understand certain details and name functions/data more adequately.
Run `maker` to build the examples. The executables will be directly placed
into this directory.

View File

@ -1,5 +1,12 @@
; Basic keyboard input function in this game, resets and updates all three
; variables according to the keyboard state.
;
; The key state is checked twice, 614.4 µs apart, to ignore the momentary "key
; released" events sent by PC-98 keyboards at the typematic rate if a key is
; held down. This ensures that the game consistently sees that specific input
; being pressed. See the HOLDKEY example in the Research/ subdirectory for
; more explanation and sample code showing off this effect.
;
; void input_reset_sense_key_held();
_input_reset_sense_key_held proc far
xor ax, ax

View File

@ -1,3 +1,9 @@
; The key state is checked twice, 614.4 µs apart, to ignore the momentary "key
; released" events sent by PC-98 keyboards at the typematic rate if a key is
; held down. This ensures that the game consistently sees that specific input
; being pressed. See the HOLDKEY example in the Research/ subdirectory for
; more explanation and sample code showing off this effect.
;
; int input_reset_sense_held();
_input_reset_sense_held proc far
call _input_reset_sense