diff --git a/CHANGELOG b/CHANGELOG index 83b887ec2..9c775f6b9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,21 @@ NEXT VERSION - - + - Tandy machine type: Many registers are WRITE ONLY according to SX + documentation, yet "Troubadours" likes to read/modify/write those + registers in what appears to be hand-rolled manual modesetting code + to set up 320x200 16-color mode, so, add code to respond to reads + from those ports with zeros and print a debug message to the log + about how DOS games are not supposed to read those registers. Make + the hand-rolled modesetting work by returning 0x00, rather than 0xFF. + The code will not set up the mode correctly if 0xFF is returned, but + will if 0x00 is returned. A side effect of this is that, since one + of the registers controls the RAM address used as video memory, this + moves it down to 512KB from base memory as well, which of course + easily corrupts the very end of the MCB chain unless you enable more + than 640KB of RAM and ask DOSBox-X to emulate the full Tandy 768KB + of conventional memory. Though the game still crashes very easily, + and in the exact same manner in both DOSBox-X and DOSBox SVN, this + fix does solve the problem where the game was only able to draw + 2 out of 4 scanlines on the screen. (joncampbell123). 2025.10.07 - INT 21h AH=4Ah resize memory: Compact free blocks only at or after the diff --git a/src/hardware/vga_other.cpp b/src/hardware/vga_other.cpp index e50f82e4a..2150dda2e 100644 --- a/src/hardware/vga_other.cpp +++ b/src/hardware/vga_other.cpp @@ -944,6 +944,27 @@ static void write_tandy_reg(uint8_t val) { } } +/* You're not SUPPOSED to read Tandy registers 3D8, 3DE, 3DF, they're documented WRITE ONLY! */ +static Bitu read_tandy(Bitu port,Bitu /*iolen*/) { + LOG(LOG_VGAMISC,LOG_DEBUG)("DOS applications are NOT SUPPOSED to read Tandy register %x",(unsigned int)port); + + switch (port) { + /* "Troubadours" does not switch into Tandy 320x200 16-color by calling INT 10h. + * Instead, it has it's own hand-written code to modify registers directly. + * For whatever reason, it modifies 3DD and 3DF by reading, modifying, and writing + * the registers EVEN THOUGH Tandy documents the registers as write only. + * Returning the last written value doesn't work, because the modified values + * come out incorrect. 3DFh after modification comes out to 0xFF which maps the + * video RAM to B800h as repeating 16KB banks for example. The game works correctly + * if this code provides 0x00, not 0xFF, when it reads these specific registers. */ + case 0x3DD: + case 0x3DF: + return 0; + } + + return ~0u; +} + static void write_tandy(Bitu port,Bitu val,Bitu /*iolen*/) { switch (port) { case 0x3d8: @@ -981,7 +1002,6 @@ static void write_tandy(Bitu port,Bitu val,Bitu /*iolen*/) { // appears to be ORed with CPU A14 (to preserve some sort of // backwards compatibility?), resulting in odd pages being mapped // as 2x16kB. Implemented in vga_memory.cpp Tandy handler. - vga.tandy.line_mask = (uint8_t)(val >> 6); vga.tandy.draw_bank = val & ((vga.tandy.line_mask&2) ? 0x6 : 0x7); vga.tandy.mem_bank = (val >> 3) & 7; @@ -1297,6 +1317,18 @@ void VGA_SetupOther(void) { } if (machine==MCH_TANDY) { write_tandy( 0x3df, 0x0, 0 ); + + // according to Tandy SX documentation a lot of registers are write-only + IO_RegisterReadHandler(0x3d4,read_tandy,IO_MB); + IO_RegisterReadHandler(0x3d5,read_tandy,IO_MB); + IO_RegisterReadHandler(0x3d8,read_tandy,IO_MB); + IO_RegisterReadHandler(0x3d9,read_tandy,IO_MB); + IO_RegisterReadHandler(0x3db,read_tandy,IO_MB); + IO_RegisterReadHandler(0x3dc,read_tandy,IO_MB); + IO_RegisterReadHandler(0x3dd,read_tandy,IO_MB); + IO_RegisterReadHandler(0x3de,read_tandy,IO_MB); + IO_RegisterReadHandler(0x3df,read_tandy,IO_MB); + IO_RegisterWriteHandler(0x3d8,write_tandy,IO_MB); IO_RegisterWriteHandler(0x3d9,write_tandy,IO_MB); IO_RegisterWriteHandler(0x3da,write_tandy,IO_MB);