--- layout: post title: Debugging the IBM VGA ROM date: 2015-06-01 11:00:00 category: Video permalink: /blog/2015/06/01/ --- The IBM VGA ("Video Graphics Array") standard was introduced as part of the IBM PS/2 line of computers; it was not a feature you could purchase or install in older PC, XT or AT-compatible machines. In fact, full VGA support was not even available in all PS/2 models. Of the first four PS/2 models -- the 8086-based Model 30, the 80286-based Model 50 and Model 60, and the 80386-based Model 80 -- VGA support was available only in the three higher-end models. The Model 30 came with MCGA ("Multicolor Graphics Array") video hardware that supported a subset of VGA modes (eg, 640x480 2-color and 320x200 256-color graphics). It wasn't until October 1987 that IBM finally introduced an 8-bit ISA card that brought VGA capability to older PCs. The card was called the **IBM PS/2 Display Adapter**. However, I think the name is a bit confusing, since the card could only be used in PC, XT, and AT-compatible systems. I'll refer to it here simply as the IBM VGA. The VGA ROM used here is assumed to have come from an original IBM VGA. It's unknown if IBM ever made any revisions to the VGA ROM. With the introduction of the PS/2 family and the VGA, IBM decided to no longer publish the source code for its ROMs, so I've created some assemblable source code from the IBM VGA ROM [here](/devices/pcx86/video/ibm/vga/). I've finally started debugging a machine configuration that uses the IBM VGA ROM. Since the VGA and the 80386 are contemporaries, I'm using an [80386 machine configuration](/devices/pcx86/machine/compaq/deskpro386/vga/2048kb/debugger/). However, I don't expect the IBM VGA ROM to require any 80386 support or PS/2-specific features. The first problem I ran into was here: ; ; Initialize the ROM BIOS Video Mode Options byte @40:0087 (default to color and 256Kb of RAM) ; mov byte [0x487],0x60 ; 0000008D ; ; The x100 subroutine alternately enables port 0x3B? and 0x3D? decoding, verifying that there is ; no response on opposing ports 0x3D? and 0x3B?, respectively; otherwise, it assumes that another ; video card must exist and attempts to select co-existing settings for the VGA. For example, if ; there is an unexpected response on the color ports, the VGA ROM will default to mono operation. ; call x100 ; 00000092 The Video component installs I/O port handlers for all possible I/O ranges; when a range isn't being used, the associated I/O operations are redirected to a dummy Card, so that the active Card isn't affected. Here, however, that was insufficient. If the VGA is the only installed video card, the VGA ROM expects *NO RESPONSE* on inactive CRTC ports. So I've changed the CRTC I/O handlers to check the Card's fActive flag. This seems like a safe and logical change, but I still have to check for backward-compatibility issues with older ROMs. Other problems included: * Some bugs in Read Mode 1 that caused a memory test failure * Horizontal and vertical retrace timing issues (the ROM requires a specific number of intervals per second) * Differences between the EGA and VGA in the SWSENSE bit (bit 4) of Input Status Register 0 The last problem was the most puzzling, because the ROM programs a series of values into the first DAC register, and expects the SWSENSE bit of Input Status Register 0 to change in very specific ways, depending on the kind of monitor attached. I've not found any hardware documentation that explains exactly how this should work. IBM's own Technical Reference material is extremely vague: "Bit 4: Switch Sense Bit - This bit allows the system microprocessor to read the switch sense line. This bit allows the power-on self-test to determine if a monochrome or color display is connected to the system." I've hard-coded a solution that assumes a color monitor. Support for using a monochrome monitor with an EGA was never completed, and this is another related issue that will have to be resolved for the VGA as well. --- While debugging and fixing assorted IBM VGA issues, I made a table of all the register values for the video modes commonly used on the IBM VGA. Here's that table: INT 0x10 Mode Requested: 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x0D 0x0E 0x10 0x12 0x13 BIOSMODE: 0x01 0x01 0x03 0x03 0x04 0x04 0x06 0x0D 0x0E 0x10 0x12 0x13 CRTC[0x00]: HTOTAL 0x2D 0x2D 0x5F 0x5F 0x2D 0x2D 0x5F 0x2D 0x5F 0x5F 0x5F 0x5F CRTC[0x01]: HDISP_END 0x27 0x27 0x4F 0x4F 0x27 0x27 0x4F 0x27 0x4F 0x4F 0x4F 0x4F CRTC[0x02]: HBLANK_START 0x28 0x28 0x50 0x50 0x28 0x28 0x50 0x28 0x50 0x50 0x50 0x50 CRTC[0x03]: HBLANK_END 0x90 0x90 0x82 0x82 0x90 0x90 0x82 0x90 0x82 0x82 0x82 0x82 CRTC[0x04]: HRETRACE_START 0x2B 0x2B 0x55 0x55 0x2B 0x2B 0x54 0x2B 0x54 0x54 0x54 0x54 CRTC[0x05]: HRETRACE_END 0xA0 0xA0 0x81 0x81 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 CRTC[0x06]: VTOTAL 0xBF 0xBF 0xBF 0xBF 0xBF 0xBF 0xBF 0xBF 0xBF 0xBF 0x0B 0xBF CRTC[0x07]: OVERFLOW 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x3E 0x1F CRTC[0x08]: PRESET_ROW 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 CRTC[0x09]: MAX_SCAN 0x4F 0x4F 0x4F 0x4F 0xC1 0xC1 0xC1 0xC0 0xC0 0x40 0x40 0x41 CRTC[0x0A]: CURSOR_START 0x0D 0x0D 0x0D 0x0D 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 CRTC[0x0B]: CURSOR_END 0x0E 0x0E 0x0E 0x0E 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 CRTC[0x0C]: START_ADDR_HI 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 CRTC[0x0D]: START_ADDR_LO 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 CRTC[0x0E]: CURSOR_ADDR_HI 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x00 CRTC[0x0F]: CURSOR_ADDR_LO 0x19 0x19 0x41 0x41 0x19 0x19 0x41 0x19 0x41 0x41 0xE1 0xA2 CRTC[0x10]: VRETRACE_START 0x9C 0x9C 0x9C 0x9C 0x9C 0x9C 0x9C 0x9C 0x9C 0x83 0xEA 0x9C CRTC[0x11]: VRETRACE_END 0x8E 0x8E 0x8E 0x8E 0x8E 0x8E 0x8E 0x8E 0x8E 0x85 0x8C 0x8E CRTC[0x12]: VDISP_END 0x8F 0x8F 0x8F 0x8F 0x8F 0x8F 0x8F 0x8F 0x8F 0x5D 0xDF 0x8F CRTC[0x13]: OFFSET 0x14 0x14 0x28 0x28 0x14 0x14 0x28 0x14 0x28 0x28 0x28 0x28 CRTC[0x14]: UNDERLINE 0x1F 0x1F 0x1F 0x1F 0x00 0x00 0x00 0x00 0x00 0x0F 0x00 0x40 CRTC[0x15]: VBLANK_START 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x63 0xE7 0x96 CRTC[0x16]: VBLANK_END 0xB9 0xB9 0xB9 0xB9 0xB9 0xB9 0xB9 0xB9 0xB9 0xBA 0x04 0xB9 CRTC[0x17]: MODE_CTRL 0xA3 0xA3 0xA3 0xA3 0xA2 0xA2 0xC2 0xE3 0xE3 0xE3 0xE3 0xA3 CRTC[0x18]: LINE_COMPARE 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF GRC[0x00]: SRESET 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 GRC[0x01]: ESRESET 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 GRC[0x02]: COLORCMP 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 GRC[0x03]: DATAROT 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 GRC[0x04]: READMAP 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 GRC[0x05]: MODE 0x10 0x10 0x10 0x10 0x30 0x30 0x00 0x00 0x00 0x00 0x00 0x40 GRC[0x06]: MISC 0x0E 0x0E 0x0E 0x0E 0x0F 0x0F 0x0D 0x05 0x05 0x05 0x05 0x05 GRC[0x07]: COLORDC 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x0F 0x0F 0x0F 0x0F 0x0F GRC[0x08]: BITMASK 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF SEQ[0x00]: RESET 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 SEQ[0x01]: CLOCKING 0x08 0x08 0x00 0x00 0x09 0x09 0x01 0x09 0x01 0x01 0x01 0x01 SEQ[0x02]: MAPMASK 0x03 0x03 0x03 0x03 0x03 0x03 0x01 0x0F 0x0F 0x0F 0x0F 0x0F SEQ[0x03]: CHARMAP 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 SEQ[0x04]: MEMMODE 0x03 0x03 0x03 0x03 0x02 0x02 0x06 0x06 0x06 0x06 0x06 0x0E ATC[0x00]: PAL00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ATC[0x01]: PAL01 0x01 0x01 0x01 0x01 0x13 0x13 0x17 0x01 0x01 0x01 0x01 0x01 ATC[0x02]: PAL02 0x02 0x02 0x02 0x02 0x15 0x15 0x17 0x02 0x02 0x02 0x02 0x02 ATC[0x03]: PAL03 0x03 0x03 0x03 0x03 0x17 0x17 0x17 0x03 0x03 0x03 0x03 0x03 ATC[0x04]: PAL04 0x04 0x04 0x04 0x04 0x02 0x02 0x17 0x04 0x04 0x04 0x04 0x04 ATC[0x05]: PAL05 0x05 0x05 0x05 0x05 0x04 0x04 0x17 0x05 0x05 0x05 0x05 0x05 ATC[0x06]: PAL06 0x14 0x14 0x14 0x14 0x06 0x06 0x17 0x06 0x06 0x14 0x14 0x06 ATC[0x07]: PAL07 0x07 0x07 0x07 0x07 0x07 0x07 0x17 0x07 0x07 0x07 0x07 0x07 ATC[0x08]: PAL08 0x38 0x38 0x38 0x38 0x10 0x10 0x17 0x10 0x10 0x38 0x38 0x08 ATC[0x09]: PAL09 0x39 0x39 0x39 0x39 0x11 0x11 0x17 0x11 0x11 0x39 0x39 0x09 ATC[0x0A]: PAL0A 0x3A 0x3A 0x3A 0x3A 0x12 0x12 0x17 0x12 0x12 0x3A 0x3A 0x0A ATC[0x0B]: PAL0B 0x3B 0x3B 0x3B 0x3B 0x13 0x13 0x17 0x13 0x13 0x3B 0x3B 0x0B ATC[0x0C]: PAL0C 0x3C 0x3C 0x3C 0x3C 0x14 0x14 0x17 0x14 0x14 0x3C 0x3C 0x0C ATC[0x0D]: PAL0D 0x3D 0x3D 0x3D 0x3D 0x15 0x15 0x17 0x15 0x15 0x3D 0x3D 0x0D ATC[0x0E]: PAL0E 0x3E 0x3E 0x3E 0x3E 0x16 0x16 0x17 0x16 0x16 0x3E 0x3E 0x0E ATC[0x0F]: PAL0F 0x3F 0x3F 0x3F 0x3F 0x17 0x17 0x17 0x17 0x17 0x3F 0x3F 0x0F ATC[0x10]: MODE 0x0C 0x0C 0x0C 0x0C 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x41 ATC[0x11]: OVERSCAN 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ATC[0x12]: PLANES 0x0F 0x0F 0x0F 0x0F 0x03 0x03 0x01 0x0F 0x0F 0x0F 0x0F 0x0F ATC[0x13]: HPAN 0x08 0x08 0x08 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 In addition, I've created a [VGA Tests](/tests/pc/vga/) directory to hold VGA test and sample code that PCjs can now successfully run (for the most part). See that directory for more details. *[@jeffpar](http://twitter.com/jeffpar)* *June 1, 2015 (Updated July 9, 2015)*