diff --git a/include/vga.h b/include/vga.h index b45a82fa..ab79466c 100644 --- a/include/vga.h +++ b/include/vga.h @@ -427,6 +427,10 @@ void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal); void VGA_DAC_SetEntry(Bitu entry,Bit8u red,Bit8u green,Bit8u blue); void VGA_ATTR_SetPalette(Bit8u index,Bit8u val); +typedef enum {CGA, EGA, MONO} EGAMonitorMode; + +void VGA_ATTR_SetEGAMonitorPalette(EGAMonitorMode m); + /* The VGA Subfunction startups */ void VGA_SetupAttr(void); void VGA_SetupMemory(Section* sec); diff --git a/src/hardware/vga_attr.cpp b/src/hardware/vga_attr.cpp index 4df8bf64..df61a7f8 100644 --- a/src/hardware/vga_attr.cpp +++ b/src/hardware/vga_attr.cpp @@ -23,22 +23,70 @@ #define attr(blah) vga.attr.blah -void VGA_ATTR_SetPalette(Bit8u index,Bit8u val) { - vga.attr.palette[index] = val; - if (vga.attr.mode_control & 0x80) val = (val&0xf) | (vga.attr.color_select << 4); - val &= 63; - val |= (vga.attr.color_select & 0xc) << 4; - if (GCC_UNLIKELY(machine==MCH_EGA)) { - if ((vga.crtc.vertical_total | ((vga.crtc.overflow & 1) << 8)) == 260) { - // check for intensity bit - if (val&0x10) val|=0x38; - else { - val&=0x7; - // check for special brown - if (val==6) val=0x14; +void VGA_ATTR_SetEGAMonitorPalette(EGAMonitorMode m) { + // palette bit assignment: + // bit | pin | EGA | CGA | monochrome + // ----+-----+------------+-----------+------------ + // 0 | 5 | blue | blue | nc + // 1 | 4 | green | green* | nc + // 2 | 3 | red | red* | nc + // 3 | 7 | blue sec. | nc | video + // 4 | 6 | green sec. | intensity | intensity + // 5 | 2 | red sec. | nc | nc + // 6-7 | not used + // * additive color brown instead of yellow + switch(m) { + case CGA: + //LOG_MSG("Monitor CGA"); + for (Bitu i=0;i<64;i++) { + vga.dac.rgb[i].red=((i & 0x4)? 0x2a:0) + ((i & 0x10)? 0x15:0); + vga.dac.rgb[i].blue=((i & 0x1)? 0x2a:0) + ((i & 0x10)? 0x15:0); + + // replace yellow with brown + if ((i & 0x17) == 0x6) vga.dac.rgb[i].green = 0x15; + else vga.dac.rgb[i].green = + ((i & 0x2)? 0x2a:0) + ((i & 0x10)? 0x15:0); } - } + break; + case EGA: + //LOG_MSG("Monitor EGA"); + for (Bitu i=0;i<64;i++) { + vga.dac.rgb[i].red=((i & 0x4)? 0x2a:0) + ((i & 0x20)? 0x15:0); + vga.dac.rgb[i].green=((i & 0x2)? 0x2a:0) + ((i & 0x10)? 0x15:0); + vga.dac.rgb[i].blue=((i & 0x1)? 0x2a:0) + ((i & 0x8)? 0x15:0); + } + break; + case MONO: + //LOG_MSG("Monitor MONO"); + for (Bitu i=0;i<64;i++) { + Bit8u value = ((i & 0x8)? 0x2a:0) + ((i & 0x10)? 0x15:0); + vga.dac.rgb[i].red = vga.dac.rgb[i].green = + vga.dac.rgb[i].blue = value; + } + break; } + + // update the mappings + for (Bit8u i=0;i<0x10;i++) + VGA_ATTR_SetPalette(i,vga.attr.palette[i]); +} + +void VGA_ATTR_SetPalette(Bit8u index, Bit8u val) { + // the attribute table stores only 6 bits + val &= 63; + vga.attr.palette[index] = val; + + // apply the plane mask + val = vga.attr.palette[index & vga.attr.color_plane_enable]; + + // replace bits 4-5 if configured + if (vga.attr.mode_control & 0x80) + val = (val&0xf) | (vga.attr.color_select << 4); + + // set bits 6 and 7 (not relevant for EGA) + val |= (vga.attr.color_select & 0xc) << 4; + + // apply VGA_DAC_CombineColor(index,val); } @@ -126,7 +174,14 @@ void write_p3c0(Bitu /*port*/,Bitu val,Bitu iolen) { break; case 0x12: /* Color Plane Enable Register */ /* Why disable colour planes? */ - attr(color_plane_enable)=(Bit8u)val; + /* To support weird modes. */ + if ((attr(color_plane_enable)^val) & 0xf) { + // in case the plane enable bits change... + attr(color_plane_enable)=(Bit8u)val; + for (Bit8u i=0;i<0x10;i++) + VGA_ATTR_SetPalette(i,vga.attr.palette[i]); + } else + attr(color_plane_enable)=(Bit8u)val; /* 0 Bit plane 0 is enabled if set. 1 Bit plane 1 is enabled if set. @@ -180,9 +235,8 @@ void write_p3c0(Bitu /*port*/,Bitu val,Bitu iolen) { } if (attr(color_select) ^ val) { attr(color_select)=(Bit8u)val; - for (Bit8u i=0;i<0x10;i++) { + for (Bit8u i=0;i<0x10;i++) VGA_ATTR_SetPalette(i,vga.attr.palette[i]); - } } /* 0-1 If 3C0h index 10h bit 7 is set these 2 bits are used as bits 4-5 of diff --git a/src/hardware/vga_dac.cpp b/src/hardware/vga_dac.cpp index b575ebb2..ae305e03 100644 --- a/src/hardware/vga_dac.cpp +++ b/src/hardware/vga_dac.cpp @@ -213,19 +213,5 @@ void VGA_SetupDAC(void) { IO_RegisterReadHandler(0x3c8,read_p3c8,IO_MB); IO_RegisterWriteHandler(0x3c9,write_p3c9,IO_MB); IO_RegisterReadHandler(0x3c9,read_p3c9,IO_MB); - } else if (machine==MCH_EGA) { - for (Bitu i=0;i<64;i++) { - if ((i&4)>0) vga.dac.rgb[i].red=0x2a; - else vga.dac.rgb[i].red=0; - if ((i&32)>0) vga.dac.rgb[i].red+=0x15; - - if ((i&2)>0) vga.dac.rgb[i].green=0x2a; - else vga.dac.rgb[i].green=0; - if ((i&16)>0) vga.dac.rgb[i].green+=0x15; - - if ((i&1)>0) vga.dac.rgb[i].blue=0x2a; - else vga.dac.rgb[i].blue=0; - if ((i&8)>0) vga.dac.rgb[i].blue+=0x15; - } } } diff --git a/src/hardware/vga_draw.cpp b/src/hardware/vga_draw.cpp index ad38ada7..ce56a52a 100644 --- a/src/hardware/vga_draw.cpp +++ b/src/hardware/vga_draw.cpp @@ -1233,6 +1233,29 @@ void VGA_SetupDrawing(Bitu /*val*/) { // Display end vga.draw.delay.vdend = vdend * vga.draw.delay.htotal; + // EGA frequency dependent monitor palette + if (machine == MCH_EGA) { + if (vga.misc_output & 1) { + // EGA card is in color mode + if ((1.0f/vga.draw.delay.htotal) > 19.0f) { + // 64 color EGA mode + VGA_ATTR_SetEGAMonitorPalette(EGA); + } else { + // 16 color CGA mode compatibility + VGA_ATTR_SetEGAMonitorPalette(CGA); + } + } else { + // EGA card in monochrome mode + // It is not meant to be autodetected that way, you either + // have a monochrome or color monitor connected and + // the EGA switches configured appropriately. + // But this would only be a problem if a program sets + // the adapter to monochrome mode and still expects color output. + // Such a program should be shot to the moon... + VGA_ATTR_SetEGAMonitorPalette(MONO); + } + } + vga.draw.parts_total=VGA_PARTS; /* 6 Horizontal Sync Polarity. Negative if set diff --git a/src/ints/int10_modes.cpp b/src/ints/int10_modes.cpp index 2b4efb30..efc46eec 100644 --- a/src/ints/int10_modes.cpp +++ b/src/ints/int10_modes.cpp @@ -1046,6 +1046,8 @@ bool INT10_SetVideoMode(Bit16u mode) { break; case M_LIN4: case M_EGA: + if (CurMode->mode == 0x0f) + gfx_data[0x7]=0x05; // only planes 0 and 2 are used gfx_data[0x6]|=0x05; //graphics mode at 0xa000-affff break; case M_CGA4: @@ -1075,12 +1077,14 @@ bool INT10_SetVideoMode(Bit16u mode) { att_data[0x10]=0x01; //Color Graphics switch (CurMode->mode) { case 0x0f: - att_data[0x10]|=0x0a; //Monochrome - att_data[0x01]=0x08; - att_data[0x04]=0x18; - att_data[0x05]=0x18; - att_data[0x09]=0x08; - att_data[0x0d]=0x18; + att_data[0x12]=0x05; // planes 0 and 2 enabled + att_data[0x10]|=0x0a; // monochrome and blinking + + att_data[0x01]=0x08; // low-intensity + att_data[0x04]=0x18; // blink-on case + att_data[0x05]=0x18; // high-intensity + att_data[0x09]=0x08; // low-intensity in blink-off case + att_data[0x0d]=0x18; // high-intensity in blink-off break; case 0x11: for (i=1;i<16;i++) att_data[i]=0x3f;