First post, by NewRisingSun
Rank
Oldbie
It would seem that the simplest way for a game to detect whether it is running on an IBM PCjr is to check whether the model id byte at F000:FFFE has the value FD. But apparently, that would be far too easy. I have seen several other methods:
- Pitstop II checks whether the byte at F000:FFF2 is 00. On the IBM PC and all machines that claim 100% IBM PC compatibility, F000:FFF0 will contain the instruction JMP F000:E05B, so F000:FFF2 will be E0. Only the PCjr jumps to F000:0043, so F000:FFF2 will indeed be 00. Because DOSBox does not emulate this particular method of PCjr detection, Pitstop II's PCjr graphics support goes unnoticed in DOSBox. (There is however at least one hacked version of the game out there which replaces the detection code with the more conventional model id query.)
- The key disk protection scheme Formaster Copylock checks whether the byte at F000:EFC8 is 03. This is the first byte of the BIOS diskette parameters table, which contains the data byte for the Floppy Disk Controller's "Specify" command. On a regular PC, this byte is 02, which will set the Floppy Disk Controller to DMA mode. Since the PCjr has no DMA controller, this byte is 03, which will set the Floppy Disk Controller to non-DMA mode. Since DOSBox does not emulate any key disk protection, it will not be necessary to emulate this method of PCjr detection.
- Sierra's HomeWord calls INT 11 and checks whether AX bit 8 is set, indicating the absence of a DMA controller. DOSBox emulates this method of PCjr detection; the source code comment indicates that The Ancient Art of War uses this detection method as well.
- Zaxxon's boot sector code checks bit 6 of I/O address 61. If it is set, the PC version is loaded; if it is cleared, the PCjr version is loaded. (The PCjr version has identical graphics but uses the TI chip for sound.) Bit 6 will always be set on a PC because clearing it would hold the keyboard clock line low. It is always clear on a PCjr or original Tandy 1000 because BIOS sets the Sound Multiplexer's source to the 8253 PIT. This is not emulated in DOSBox, where bit 6 is always clear regardless of machine type.
Method 1 could be emulated for Pitstop II to display 16 color RGB graphics by replacing this section of ints\bios.cpp:
phys_writeb(0xFFFF0,0xEA); // FARJMP
phys_writew(0xFFFF1,RealOff(BIOS_DEFAULT_RESET_LOCATION)); // offset
phys_writew(0xFFFF3,RealSeg(BIOS_DEFAULT_RESET_LOCATION)); // segment
// Compatible POST routine location: jump to the callback
phys_writeb(Real2Phys(BIOS_DEFAULT_RESET_LOCATION)+0,0xEA); // FARJMP
phys_writew(Real2Phys(BIOS_DEFAULT_RESET_LOCATION)+1,RealOff(rptr)); // offset
phys_writew(Real2Phys(BIOS_DEFAULT_RESET_LOCATION)+3,RealSeg(rptr)); // segment
with this:
if (machine == MCH_PCJR) {
#define BIOS_PCJR_RESET_LOCATION (RealMake(0xf000,0x0043))
phys_writeb(0xFFFF0,0xEA); // FARJMP
phys_writew(0xFFFF1,RealOff(BIOS_PCJR_RESET_LOCATION)); // offset
phys_writew(0xFFFF3,RealSeg(BIOS_PCJR_RESET_LOCATION)); // segment
// Compatible POST routine location: jump to the callback
phys_writeb(Real2Phys(BIOS_PCJR_RESET_LOCATION)+0,0xEA); // FARJMP
phys_writew(Real2Phys(BIOS_PCJR_RESET_LOCATION)+1,RealOff(rptr)); // offset
phys_writew(Real2Phys(BIOS_PCJR_RESET_LOCATION)+3,RealSeg(rptr)); // segment
} else {
phys_writeb(0xFFFF0,0xEA); // FARJMP
phys_writew(0xFFFF1,RealOff(BIOS_DEFAULT_RESET_LOCATION)); // offset
phys_writew(0xFFFF3,RealSeg(BIOS_DEFAULT_RESET_LOCATION)); // segment
// Compatible POST routine location: jump to the callback
phys_writeb(Real2Phys(BIOS_DEFAULT_RESET_LOCATION)+0,0xEA); // FARJMP
phys_writew(Real2Phys(BIOS_DEFAULT_RESET_LOCATION)+1,RealOff(rptr)); // offset
phys_writew(Real2Phys(BIOS_DEFAULT_RESET_LOCATION)+3,RealSeg(rptr)); // segment
}
Method 4 could be emulated for Zaxxon to run properly on CGA by replacing this section in hardware\keyboard.cpp:
static Bit8u port_61_data = 0;
static Bitu read_p61(Bitu port,Bitu iolen) {
port_61_data^=0x20;
port_61_data^=0x10;
return port_61_data;
}
with this:
static Bit8u port_61_data = 0;
static Bitu read_p61(Bitu port,Bitu iolen) {
port_61_data^=0x20;
port_61_data^=0x10;
if (machine==MCH_CGA || machine==MCH_HERC) port_61_data^=0x40;
return port_61_data;
}