PCjr INT 48h translation

This commit is contained in:
Jonathan Campbell 2024-12-23 15:42:49 -08:00
parent 088cf64e0e
commit 36c48c5f3a
2 changed files with 40 additions and 22 deletions

View File

@ -403,32 +403,24 @@ Bitu CALLBACK_SetupExtra(Bitu callback, Bitu type, PhysPt physAddress, bool use_
phys_writeb(physAddress+0x0e,(uint8_t)0xcf); //An IRET Instruction
return (use_cb?0x13:0x0f);
case CB_IRQ1: // keyboard int9
phys_writeb(physAddress+0x00,(uint8_t)0x50); // push ax
if (machine == MCH_PCJR) {
/* IBM PCjr reads the infrared input on NMI interrupt, which then calls INT 48h to
* translate to IBM PC/XT scan codes before passing AL directly to IRQ1 (INT 9).
* PCjr keyboard handlers, including games made for the PCjr, assume the scan code
* is in AL and do not read the I/O port.
*
* PCjr has an XT style keyboard interface where it is necessary to set, then clear,
* bit 7 of port 61h to re-enable the keyboard.
*
* Because we're talking to our own emulation, it is sufficient to just clear bit 7.*/
phys_writew(physAddress+0x01,(uint16_t)0x60E4); // in al, 0x60
* is in AL and do not read the I/O port. */
if (use_cb) {
phys_writeb(physAddress+0x03,(uint8_t)0xFE); //GRP 4
phys_writeb(physAddress+0x04,(uint8_t)0x38); //Extra Callback instruction
phys_writew(physAddress+0x05,(uint16_t)callback); //The immediate word
phys_writeb(physAddress+0x00,(uint8_t)0xFE); //GRP 4
phys_writeb(physAddress+0x01,(uint8_t)0x38); //Extra Callback instruction
phys_writew(physAddress+0x02,(uint16_t)callback); //The immediate word
physAddress+=4;
}
/* It wasn't an interrupt, so there's no need to ack */
phys_writeb(physAddress+0x03,(uint8_t)0x58); // pop ax
phys_writeb(physAddress+0x04,(uint8_t)0xcf); //An IRET Instruction
return (use_cb?0x09:0x05);
phys_writeb(physAddress+0x00,(uint8_t)0xcf); //An IRET Instruction
return (use_cb?0x05:0x01);
}
else {
phys_writeb(physAddress+0x00,(uint8_t)0x50); // push ax
if (IS_PC98_ARCH) {
/* NTS: NEC PC-98 does not have keyboard input on port 60h, it's a 8251 UART elsewhere. */
phys_writew(physAddress+0x01,(uint16_t)0x9090); // nop, nop

View File

@ -1180,19 +1180,45 @@ static Bitu PCjr_NMI_Keyboard_Handler(void) {
* Fn + 1 into the scan code for F1. */
static Bitu PCjr_INT48_Keyboard_Handler(void) {
uint8_t pcjr_f = mem_readb(BIOS_KEYBOARD_PCJR_FLAG2);
uint8_t flags1 = mem_readb(BIOS_KEYBOARD_FLAGS1);
switch (reg_al&0x7F) {
case 0x54: /* Fn key */
if (reg_al&0x80/*release*/) pcjr_f &= ~BIOS_KEYBOARD_PCJR_FLAG2_FN_FLAG;
else pcjr_f |= BIOS_KEYBOARD_PCJR_FLAG2_FN_FLAG;
goto skip_int9;
default: /* AL without translation */
break;
if ((reg_al&0x7F) == 0x54) {
if (reg_al&0x80/*release*/) pcjr_f &= ~BIOS_KEYBOARD_PCJR_FLAG2_FN_FLAG;
else pcjr_f |= BIOS_KEYBOARD_PCJR_FLAG2_FN_FLAG;
goto skip_int9;
}
#define UPDATESHIFT(x) if (x) { flags1 &= ~0x3; /*break*/ } else { flags1 |= 0x3; /*make*/ }
#define CLEARSHIFT() UPDATESHIFT(1/*break*/)
if (pcjr_f & (BIOS_KEYBOARD_PCJR_FLAG2_FN_FLAG|BIOS_KEYBOARD_PCJR_FLAG2_FN_LOCK)) {
const uint8_t bc = reg_al & 0x80;
switch (reg_al&0x7F) {
case 0x02: reg_al=0x3B|bc; break;/*Fn+1 = F1*/
case 0x03: reg_al=0x3C|bc; break;/*Fn+2 = F2*/
case 0x04: reg_al=0x3D|bc; break;/*Fn+3 = F3*/
case 0x05: reg_al=0x3E|bc; break;/*Fn+4 = F4*/
case 0x06: reg_al=0x3F|bc; break;/*Fn+5 = F5*/
case 0x07: reg_al=0x40|bc; break;/*Fn+6 = F6*/
case 0x08: reg_al=0x41|bc; break;/*Fn+7 = F7*/
case 0x09: reg_al=0x42|bc; break;/*Fn+8 = F8*/
case 0x0A: reg_al=0x43|bc; break;/*Fn+9 = F9*/
case 0x0B: reg_al=0x44|bc; break;/*Fn+10 = F10*/
case 0x1A: reg_al=0x2B|bc; UPDATESHIFT(bc); break;/*Fn+[ = | which is SHIFT+\ */
case 0x1B: reg_al=0x29|bc; UPDATESHIFT(bc); break;/*Fn+] = ~ which is SHIFT+` */
case 0x28: reg_al=0x29|bc; CLEARSHIFT(); break;/*Fn+' = ` which is unshifted ` */
case 0x35: reg_al=0x2B|bc; CLEARSHIFT(); break;/*Fn+/ = \\ which is unshifted \\ */
default: break;
}
}
#undef UPDATESHIFT
#undef CLEARSHIFT
reg_eip++; /* skip over IRET */
skip_int9: /* if we do not skip IRET, then INT 48h returns without calling INT 9h */
mem_writeb(BIOS_KEYBOARD_FLAGS1,flags1);
mem_writeb(BIOS_KEYBOARD_PCJR_FLAG2,pcjr_f);
return CBRET_NONE;
}