DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/hardware/vga_seq.cpp
00001 /*
00002  *  Copyright (C) 2002-2015  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 #include "dosbox.h"
00021 #include "inout.h"
00022 #include "vga.h"
00023 
00024 #define seq(blah) vga.seq.blah
00025 
00026 Bitu read_p3c4(Bitu /*port*/,Bitu /*iolen*/) {
00027         return seq(index);
00028 }
00029 
00030 void write_p3c4(Bitu /*port*/,Bitu val,Bitu /*iolen*/) {
00031         // FIXME: Standard VGA behavior (based on observation) is to latch
00032         //        the sequencer register based only on the lowest 4 bits.
00033         //        Thus, the map mask register is accessible not only by index 0x02,
00034         //        but also from 0x12, 0x22, etc..
00035         //
00036         //        This isn't quite universal, as WHATVGA documentation suggests
00037         //        there are SVGA chipsets with extended registers in the 0x07-0x17
00038         //        and 0x80-0x9F ranges. But register snapshots so far seem to suggest
00039         //        most cards just mask off the index to 4 bits and put the extended
00040         //        regs elsewhere.
00041         //
00042         //        The yet to be answered question is: if the card only latches the
00043         //        low 4 bits, then what will you see when you read back the sequencer
00044         //        index register? Will you see the full 8-bit value, or the low 4 bits
00045         //        it actually decoded?
00046         //
00047         // FIXME: I don't have an EGA to test with, but, what masking behavior here
00048         //        do EGA and compatibles do with the index?
00049 
00050         /* Emulating the mask behavior fixes the following problems with games & demoscene entries:
00051          *
00052          * - "Spiral" by Dataction: SPIRAL.EXE appears to use VGA Mode-X 256-color mode, but it relies
00053          *   on sequencer alias register 0x12 for masking bitplanes instead of properly writing
00054          *   Map Mask Register (register 0x02). Older VGA chipsets only decoded 3 or 4 bits of the sequencer
00055          *   index register, so this happened to work anyway since (0x12 & 0x0F) == 0x02, but it also means
00056          *   the demo will not render Mode X properly on newer SVGA chipsets that decode more than 4 bits of
00057          *   the sequencer index register. Adding this masking behavior, and running the demo
00058          *   with machine=svga_et4000 allows the demo to display properly instead of rendering as
00059          *   a blocky low-res mess.
00060          *   [http://www.pouet.net/prod.php?which=12630]
00061          */
00062 
00063         if (machine == MCH_VGA) {
00064                 if (svgaCard == SVGA_S3Trio)
00065                         val &= 0x3F;    // observed behavior: only the low 6 bits
00066                 else if (svgaCard == SVGA_TsengET4K)
00067                         val &= 0x07;    // observed behavior: only the low 3 bits
00068                 else if (svgaCard == SVGA_TsengET3K)
00069                         val &= 0x07;    // FIXME: reasonable guess, since the ET4000 does it too
00070                 else
00071                         val &= 0x0F;    // FIXME: reasonable guess
00072         }
00073         else if (machine == MCH_EGA) {
00074                 val &= 0x0F; // FIXME: reasonable guess
00075         }
00076 
00077         seq(index)=val;
00078 }
00079 
00080 void VGA_SequReset(bool reset);
00081 void VGA_Screenstate(bool enabled);
00082 
00083 void write_p3c5(Bitu /*port*/,Bitu val,Bitu iolen) {
00084 //      LOG_MSG("SEQ WRITE reg %X val %X",seq(index),val);
00085         switch(seq(index)) {
00086         case 0:         /* Reset */
00087                 if((seq(reset)^val)&0x3) VGA_SequReset((val&0x3)!=0x3);
00088                 seq(reset)=val;
00089                 break;
00090         case 1:         /* Clocking Mode */
00091                 if (val!=seq(clocking_mode)) {
00092                         if((seq(clocking_mode)^val)&0x20) VGA_Screenstate((val&0x20)==0);
00093                         // don't resize if only the screen off bit was changed
00094                         if ((val&(~0x20u))!=(seq(clocking_mode)&(~0x20u))) {
00095                                 seq(clocking_mode)=val;
00096                                 VGA_StartResize();
00097                         } else {
00098                                 seq(clocking_mode)=val;
00099                         }
00100                         if (val & 0x20) vga.attr.disabled |= 0x2u;
00101                         else vga.attr.disabled &= ~0x2u;
00102                 }
00103                 /* TODO Figure this out :)
00104                         0       If set character clocks are 8 dots wide, else 9.
00105                         2       If set loads video serializers every other character
00106                                 clock cycle, else every one.
00107                         3       If set the Dot Clock is Master Clock/2, else same as Master Clock
00108                                 (See 3C2h bit 2-3). (Doubles pixels). Note: on some SVGA chipsets
00109                                 this bit also affects the Sequencer mode.
00110                         4       If set loads video serializers every fourth character clock cycle,
00111                                 else every one.
00112                         5       if set turns off screen and gives all memory cycles to the CPU
00113                                 interface.
00114                 */
00115                 break;
00116         case 2:         /* Map Mask */
00117                 seq(map_mask)=val & 15;
00118                 vga.config.full_map_mask=FillTable[val & 15];
00119                 vga.config.full_not_map_mask=~vga.config.full_map_mask;
00120                 /*
00121                         0  Enable writes to plane 0 if set
00122                         1  Enable writes to plane 1 if set
00123                         2  Enable writes to plane 2 if set
00124                         3  Enable writes to plane 3 if set
00125                 */
00126                 break;
00127         case 3:         /* Character Map Select */
00128                 {
00129                         seq(character_map_select)=val;
00130                         Bit8u font1=(val & 0x3) << 1;
00131                         if (IS_VGA_ARCH) font1|=(val & 0x10) >> 4;
00132                         vga.draw.font_tables[0]=&vga.draw.font[font1*8*1024];
00133                         Bit8u font2=((val & 0xc) >> 1);
00134                         if (IS_VGA_ARCH) font2|=(val & 0x20) >> 5;
00135                         vga.draw.font_tables[1]=&vga.draw.font[font2*8*1024];
00136                 }
00137                 /*
00138                         0,1,4  Selects VGA Character Map (0..7) if bit 3 of the character
00139                                         attribute is clear.
00140                         2,3,5  Selects VGA Character Map (0..7) if bit 3 of the character
00141                                         attribute is set.
00142                         Note: Character Maps are placed as follows:
00143                         Map 0 at 0k, 1 at 16k, 2 at 32k, 3: 48k, 4: 8k, 5: 24k, 6: 40k, 7: 56k
00144                 */
00145                 break;
00146         case 4: /* Memory Mode */
00147                 /* 
00148                         0  Set if in an alphanumeric mode, clear in graphics modes.
00149                         1  Set if more than 64kbytes on the adapter.
00150                         2  Enables Odd/Even addressing mode if set. Odd/Even mode places all odd
00151                                 bytes in plane 1&3, and all even bytes in plane 0&2.
00152                         3  If set address bit 0-1 selects video memory planes (256 color mode),
00153                                 rather than the Map Mask and Read Map Select Registers.
00154                 */
00155                 seq(memory_mode)=val;
00156                 if (IS_VGA_ARCH) {
00157                         /* Changing this means changing the VGA Memory Read/Write Handler */
00158                         if (val&0x08) vga.config.chained=true;
00159                         else vga.config.chained=false;
00160                         VGA_SetupHandlers();
00161                 }
00162                 break;
00163         default:
00164                 if (svga.write_p3c5) {
00165                         svga.write_p3c5(seq(index), val, iolen);
00166                 } else {
00167                         LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:SEQ:Write to illegal index %2X",seq(index));
00168                 }
00169                 break;
00170         }
00171 }
00172 
00173 
00174 Bitu read_p3c5(Bitu /*port*/,Bitu iolen) {
00175 //      LOG_MSG("VGA:SEQ:Read from index %2X",seq(index));
00176         switch(seq(index)) {
00177         case 0:                 /* Reset */
00178                 return seq(reset);
00179                 break;
00180         case 1:                 /* Clocking Mode */
00181                 return seq(clocking_mode);
00182                 break;
00183         case 2:                 /* Map Mask */
00184                 return seq(map_mask);
00185                 break;
00186         case 3:                 /* Character Map Select */
00187                 return seq(character_map_select);
00188                 break;
00189         case 4:                 /* Memory Mode */
00190                 return seq(memory_mode);
00191                 break;
00192         default:
00193                 if (svga.read_p3c5)
00194                         return svga.read_p3c5(seq(index), iolen);
00195                 break;
00196         }
00197         return 0;
00198 }
00199 
00200 
00201 void VGA_SetupSEQ(void) {
00202         if (IS_EGAVGA_ARCH) {
00203                 IO_RegisterWriteHandler(0x3c4,write_p3c4,IO_MB);
00204                 IO_RegisterWriteHandler(0x3c5,write_p3c5,IO_MB);
00205                 if (IS_VGA_ARCH) {
00206                         IO_RegisterReadHandler(0x3c4,read_p3c4,IO_MB);
00207                         IO_RegisterReadHandler(0x3c5,read_p3c5,IO_MB);
00208                 }
00209         }
00210 }
00211 
00212 void VGA_UnsetupSEQ(void) {
00213     IO_FreeWriteHandler(0x3c4,IO_MB);
00214     IO_FreeReadHandler(0x3c4,IO_MB);
00215     IO_FreeWriteHandler(0x3c5,IO_MB);
00216     IO_FreeReadHandler(0x3c5,IO_MB);
00217 }
00218