From 3d2f114bdaa8e5b1b7ebe1c0ef2218f12a2c908e Mon Sep 17 00:00:00 2001 From: Jonathan Campbell Date: Mon, 19 Feb 2024 13:06:20 -0800 Subject: [PATCH] PC-98: Write the PC-98 mapping table for all 10 possible states, though incomplete for anything other than normal, shift, and control. This is enough to keep Nut Berry happy and possibly any other PC-98 game that needs the keyboard translation tables to run. Update code to reflect that the lookup tables are 0x60, not 0x80 bytes long, because they skip a range of unused scan codes --- CHANGELOG | 4 +-- src/ints/bios.cpp | 16 +++++----- src/ints/bios_keyboard.cpp | 61 ++++++++++++++++++++++++++++++++++---- 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 30b333292b6..2c9d0817ad9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,8 +3,8 @@ Next: keyboard translation table pointer in the BIOS data area for "Nut Berry". This Nut Berry game also assumes lookup and translation tables exist at specific locations in the ROM BIOS, so put those tables there. The shift - state table in BIOS has also been added, though at the moment, they all - reflect the normal unshifted state which shouldn't be a problem. (joncampbell123). + state table in BIOS has also been added, though at the moment, the tables + are incomplete. (joncampbell123). - MegaZeux from the MS-DOS days had a 256-color tweakmode that worked on some popular SVGA chipsets of it's time though on others it does nothing but halve the display resolution of text mode. The basic idea is that it makes the VGA diff --git a/src/ints/bios.cpp b/src/ints/bios.cpp index 758ed391aa8..c5eeee598ee 100644 --- a/src/ints/bios.cpp +++ b/src/ints/bios.cpp @@ -10033,6 +10033,13 @@ class BIOS:public Module_base{ } } + if (IS_PC98_ARCH) { + /* Keyboard translation tables, must exist at segment 0xFD80:0x0E00 because PC-98 MS-DOS assumes it (it writes 0x522 itself on boot) */ + /* The table must be placed back far enough so that (0x60 * 10) bytes do not overlap the lookup table at 0xE28 */ + BIOS_PC98_KEYBOARD_TRANSLATION_LOCATION = PhysToReal416(ROMBIOS_GetMemory(0x60 * 10,"Keyboard translation tables",/*align*/1,0xFD800+0xA13)); + if (ROMBIOS_GetMemory(0x2 * 10,"Keyboard translation shift tables",/*align*/1,0xFD800+0xE28) == (~0u)) E_Exit("Failed to allocate shift tables");//reserve it + BIOSKEY_PC98_Write_Tables(); + } /* pick locations */ /* IBM PC mode: See [https://github.com/skiselev/8088_bios/blob/master/bios.asm]. Some values also provided by Allofich. @@ -10051,12 +10058,6 @@ class BIOS:public Module_base{ BIOS_DEFAULT_IRQ07_DEF_LOCATION = PhysToReal416(ROMBIOS_GetMemory(7/*see callback.cpp for EOI_PIC1*/,"BIOS default IRQ2-7 location",/*align*/1,IS_PC98_ARCH ? 0 : 0xFFF55)); BIOS_DEFAULT_IRQ815_DEF_LOCATION = PhysToReal416(ROMBIOS_GetMemory(9/*see callback.cpp for EOI_PIC1*/,"BIOS default IRQ8-15 location",/*align*/1,IS_PC98_ARCH ? 0 : 0xFE880)); - if (IS_PC98_ARCH) { - /* Keyboard translation tables, must exist at segment 0xFD80:0x0E00 because PC-98 MS-DOS assumes it (it writes 0x522 itself on boot) */ - BIOS_PC98_KEYBOARD_TRANSLATION_LOCATION = PhysToReal416(ROMBIOS_GetMemory(0x80/*TODO: multiple tables eventually*/,"Keyboard translation tables",/*align*/1,0xFD800+0xB31)); - BIOSKEY_PC98_Write_Tables(); - } - write_FFFF_signature(); /* Setup all the interrupt handlers the bios controls */ @@ -10419,11 +10420,10 @@ class BIOS:public Module_base{ * (0xE31 instead of 0xE28). The table mentioned here is used to update the 0x522 offset WORD in the * BIOS data area to reflect the translation table in effect based on the shift key status, so if you * misread the table you end up pointing it at junk and then keyboard input doesn't work anymore. */ - // FIXME: This implementation does not yet implement all tables! // NTS: On a real PC-9821 laptop, the table is apparently 10 entries long. If BDA byte 0x53A is less than // 8 then it's just a simple lookup. If BDA byte 0x53A has bit 4 set, then use the 8th entry, and // if bit 4 and 3 are set, use the 9th entry. - for (unsigned int i=0;i < 10;i++) phys_writew(0xFD800+0xE28+(i*2),(unsigned int)(Real2Phys(BIOS_PC98_KEYBOARD_TRANSLATION_LOCATION) - 0xFD800)); + for (unsigned int i=0;i < 10;i++) phys_writew(0xFD800+0xE28+(i*2),(unsigned int)(Real2Phys(BIOS_PC98_KEYBOARD_TRANSLATION_LOCATION) - 0xFD800) + (i * 0x60)); } else { if (ibm_rom_basic_size == 0) { diff --git a/src/ints/bios_keyboard.cpp b/src/ints/bios_keyboard.cpp index 547c478b168..b98f7a3a746 100644 --- a/src/ints/bios_keyboard.cpp +++ b/src/ints/bios_keyboard.cpp @@ -300,11 +300,62 @@ static scancode_tbl scan_to_scanascii_pc98[0x80] = { void BIOSKEY_PC98_Write_Tables(void) { unsigned int i; - Bitu o; - - /* Assume this function will not be called unless BIOS_PC98_KEYBOARD_TRANSLATION_LOCATION points to ROM BIOS */ - o = Real2Phys(BIOS_PC98_KEYBOARD_TRANSLATION_LOCATION); - for (i=0;i < 0x80;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i].normal); + Bitu o = Real2Phys(BIOS_PC98_KEYBOARD_TRANSLATION_LOCATION); + + /* Assume this function will not be called unless BIOS_PC98_KEYBOARD_TRANSLATION_LOCATION points to ROM BIOS. + * It's actually not exactly a 1:1 mapping, the empty range between 0x56-0x61 is skipped according to the + * tables on real hardare. On real hardware the tables are noticeably 0x60 (not 0x80) bytes apart from each other. + * Special processing is done for the shift state keys that do not involve the table. */ + + /* [0] Normal */ + for (i=0x00;i < 0x56;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i].normal); + for (i=0x62;i < 0x6C;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i-0xC].normal); /* NTS: 0x62-0x0C = 0x56, 10 codes fill 0x56-0x5F. 0x60-0x56 = 0x0A (10). 0x60 bytes total */ + o += 0x60; + + /* [1] Shift */ + for (i=0x00;i < 0x56;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i].shift); + for (i=0x62;i < 0x6C;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i-0xC].shift); /* NTS: 0x62-0x0C = 0x56, 10 codes fill 0x56-0x5F. 0x60-0x56 = 0x0A (10). 0x60 bytes total */ + o += 0x60; + + /* [2] Caps */ //FIXME + for (i=0x00;i < 0x56;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i].shift); + for (i=0x62;i < 0x6C;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i-0xC].shift); /* NTS: 0x62-0x0C = 0x56, 10 codes fill 0x56-0x5F. 0x60-0x56 = 0x0A (10). 0x60 bytes total */ + o += 0x60; + + /* [3] Shift+Caps */ //FIXME + for (i=0x00;i < 0x56;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i].normal); + for (i=0x62;i < 0x6C;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i-0xC].normal); /* NTS: 0x62-0x0C = 0x56, 10 codes fill 0x56-0x5F. 0x60-0x56 = 0x0A (10). 0x60 bytes total */ + o += 0x60; + + /* [4] Kana */ //FIXME + for (i=0x00;i < 0x56;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i].normal); + for (i=0x62;i < 0x6C;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i-0xC].normal); /* NTS: 0x62-0x0C = 0x56, 10 codes fill 0x56-0x5F. 0x60-0x56 = 0x0A (10). 0x60 bytes total */ + o += 0x60; + + /* [5] Kana+Shift */ //FIXME + for (i=0x00;i < 0x56;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i].shift); + for (i=0x62;i < 0x6C;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i-0xC].shift); /* NTS: 0x62-0x0C = 0x56, 10 codes fill 0x56-0x5F. 0x60-0x56 = 0x0A (10). 0x60 bytes total */ + o += 0x60; + + /* [6] Kana+Caps */ //FIXME + for (i=0x00;i < 0x56;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i].shift); + for (i=0x62;i < 0x6C;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i-0xC].shift); /* NTS: 0x62-0x0C = 0x56, 10 codes fill 0x56-0x5F. 0x60-0x56 = 0x0A (10). 0x60 bytes total */ + o += 0x60; + + /* [7] Kana+Shift+Caps */ //FIXME + for (i=0x00;i < 0x56;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i].normal); + for (i=0x62;i < 0x6C;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i-0xC].normal); /* NTS: 0x62-0x0C = 0x56, 10 codes fill 0x56-0x5F. 0x60-0x56 = 0x0A (10). 0x60 bytes total */ + o += 0x60; + + /* [8] Kana */ //FIXME + for (i=0x00;i < 0x56;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i].normal); + for (i=0x62;i < 0x6C;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i-0xC].normal); /* NTS: 0x62-0x0C = 0x56, 10 codes fill 0x56-0x5F. 0x60-0x56 = 0x0A (10). 0x60 bytes total */ + o += 0x60; + + /* [9] Kana+Shift */ //FIXME + for (i=0x00;i < 0x56;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i].shift); + for (i=0x62;i < 0x6C;i++) phys_writeb(o+i,scan_to_scanascii_pc98[i-0xC].shift); /* NTS: 0x62-0x0C = 0x56, 10 codes fill 0x56-0x5F. 0x60-0x56 = 0x0A (10). 0x60 bytes total */ + o += 0x60; } std::queue over_key_buffer;