mirror of https://github.com/nmlgc/ReC98.git
[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:
parent
cbe8a37c53
commit
8dfc2cd535
|
@ -2,3 +2,7 @@ bin/th*
|
|||
bin/TH*
|
||||
bin/zuncom
|
||||
bin/ZUNCOM
|
||||
Research/*.exe
|
||||
Research/*.obj
|
||||
RESEARCH/*.EXE
|
||||
RESEARCH/*.OBJ
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
# ReC98 Research
|
||||
# --------------
|
||||
# Makefile
|
||||
|
||||
.autodepend
|
||||
|
||||
LFLAGS = -L..\bin\
|
||||
|
||||
all: HOLDKEY.EXE
|
||||
|
||||
HOLDKEY.EXE: HOLDKEY.OBJ
|
||||
$(CC) $(LFLAGS) masters.lib $**
|
|
@ -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.
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue