From b0c5c68cc628f936fb7856824989c158f70dab39 Mon Sep 17 00:00:00 2001 From: Jonathan Campbell Date: Wed, 4 Dec 2024 20:49:32 -0800 Subject: [PATCH] INT 10h: If machine=ega, check EGA switches to detect games that alter the EGA switches to force 200-line mode --- CHANGELOG | 4 ++++ src/ints/int10.cpp | 7 +++++-- src/ints/int10_modes.cpp | 18 +++++++++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 05436ad07..915f905de 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,10 @@ Next to divide line by 2 in rendering to match double scanned scanlines, so that the "graphical" text of "After the War" can render properly for machine=vgaonly. (joncampbell123). + - INT 10: If machine=ega, check the EGA switches on INT 10h modeset. + Some games force the EGA BIOS to use CGA 200-line text modes by + modifying those bits and then setting the mode ("After the War"). + (joncampbell123). 2024.12.04 - Arrange memory device allocation so that it is possible to allocate diff --git a/src/ints/int10.cpp b/src/ints/int10.cpp index 83c50acbe..d6120db6a 100644 --- a/src/ints/int10.cpp +++ b/src/ints/int10.cpp @@ -1240,7 +1240,10 @@ static void INT10_Seg40Init(void) { // in Tandy emulation, this byte must be zero. if (IS_EGAVGA_ARCH) { real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,0x60); - real_writeb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,16); + if (IS_VGA_ARCH) + real_writeb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,16); + else + real_writeb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,ega200 ? 8 : 14); // NTS: This is direclty from the configuration switches. The bits are inverted, // 1=OFF 0=ON. // @@ -1262,7 +1265,7 @@ static void INT10_Seg40Init(void) { // [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/Video/EGA/IBM/IBM%20Enhanced%20Graphics%20Adapter%20%281984%2d08%2d02%29%2epdf] // // Anything else is not valid. - real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xFF^((!IS_VGA_ARCH && ega200)?0x8:0x6)); + real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xFF^((!IS_VGA_ARCH && ega200)?0x7:0x9)); // Set the pointer to video save pointer table real_writed(BIOSMEM_SEG, BIOSMEM_VS_POINTER, int10.rom.video_save_pointers); } diff --git a/src/ints/int10_modes.cpp b/src/ints/int10_modes.cpp index 959f7941d..5391ff3d2 100644 --- a/src/ints/int10_modes.cpp +++ b/src/ints/int10_modes.cpp @@ -887,7 +887,6 @@ static void FinishSetMode(bool clearmem) { real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,(uint8_t)(CurMode->theight-1)); real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,(uint16_t)CurMode->cheight); real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|(clearmem?0:0x80))); - real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,(!IS_VGA_ARCH && ega200)?0x08:0x09); // this is an index into the dcc table: #if C_DEBUG if(IS_VGA_ARCH) real_writeb(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,DISP2_Active()?0x0c:0x0b); @@ -1259,6 +1258,23 @@ static bool ShouldUseVPT(void) { bool unmask_irq0_on_int10_setmode = true; bool INT10_SetVideoMode(uint16_t mode) { + if (IS_EGA_ARCH) { + /* "After The War" forces EGA into 200-line CGA 8x8 text mode by + * modifying the 16-bits at 0x487-0x488 to alter the EGA switches + * and other info. For this trick to work here, we have to check + * those bits every modeset. */ + uint8_t egasw = (real_readb(BIOSMEM_SEG,BIOSMEM_SWITCHES)^0xFF)&0xF; + bool newega200 = (egasw == 0 || egasw == 1 || egasw == 2 || egasw == 6 || egasw == 7 || egasw == 8); + + if (ega200 != newega200) { + LOG(LOG_MISC,LOG_DEBUG)( + "EGA: Guest application changed BIOS DATA AREA EGA switches, %s 200-line EGA modes (sw=0x%x)", + newega200?"enabled":"disabled",egasw); + + ega200 = newega200; + } + } + if (CurMode&&CurMode->mode==7&&!IS_PC98_ARCH) { VideoModeBlock *modelist;