DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/vga_seq.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  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 along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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         /* Paradise/Western Digital sequencer registers appear to repeat every 0x40 aka decoding bits [5:0] */
00074         }
00075         else if (machine == MCH_EGA) {
00076                 val &= 0x0F; // FIXME: reasonable guess
00077         }
00078 
00079         seq(index)=(Bit8u)val;
00080 }
00081 
00082 void VGA_SequReset(bool reset);
00083 void VGA_Screenstate(bool enabled);
00084 
00085 void write_p3c5(Bitu /*port*/,Bitu val,Bitu iolen) {
00086 //      LOG_MSG("SEQ WRITE reg %X val %X",seq(index),val);
00087         switch(seq(index)) {
00088         case 0:         /* Reset */
00089                 if((seq(reset)^val)&0x3) VGA_SequReset((val&0x3)!=0x3);
00090                 seq(reset)=(Bit8u)val;
00091                 break;
00092         case 1:         /* Clocking Mode */
00093                 if (val!=seq(clocking_mode)) {
00094                         if((seq(clocking_mode)^val)&0x20) VGA_Screenstate((val&0x20)==0);
00095                         // don't resize if only the screen off bit was changed
00096                         if ((val&(~0x20u))!=(seq(clocking_mode)&(~0x20u))) {
00097                                 seq(clocking_mode)=(Bit8u)val;
00098                                 VGA_StartResize();
00099                         } else {
00100                                 seq(clocking_mode)=(Bit8u)val;
00101                         }
00102                         if (val & 0x20) vga.attr.disabled |= 0x2u;
00103                         else vga.attr.disabled &= ~0x2u;
00104                 }
00105                 /* TODO Figure this out :)
00106                         0       If set character clocks are 8 dots wide, else 9.
00107                         2       If set loads video serializers every other character
00108                                 clock cycle, else every one.
00109                         3       If set the Dot Clock is Master Clock/2, else same as Master Clock
00110                                 (See 3C2h bit 2-3). (Doubles pixels). Note: on some SVGA chipsets
00111                                 this bit also affects the Sequencer mode.
00112                         4       If set loads video serializers every fourth character clock cycle,
00113                                 else every one.
00114                         5       if set turns off screen and gives all memory cycles to the CPU
00115                                 interface.
00116                 */
00117                 break;
00118         case 2:         /* Map Mask */
00119                 seq(map_mask)=val & 15;
00120                 vga.config.full_map_mask=FillTable[val & 15];
00121                 vga.config.full_not_map_mask=~vga.config.full_map_mask;
00122                 /*
00123                         0  Enable writes to plane 0 if set
00124                         1  Enable writes to plane 1 if set
00125                         2  Enable writes to plane 2 if set
00126                         3  Enable writes to plane 3 if set
00127                 */
00128                 break;
00129         case 3:         /* Character Map Select */
00130                 {
00131                         seq(character_map_select)=(Bit8u)val;
00132                         Bit8u font1=(val & 0x3) << 1;
00133                         if (IS_VGA_ARCH) font1|=(val & 0x10) >> 4;
00134                         vga.draw.font_tables[0]=&vga.draw.font[font1*8*1024];
00135                         Bit8u font2=((val & 0xc) >> 1);
00136                         if (IS_VGA_ARCH) font2|=(val & 0x20) >> 5;
00137                         vga.draw.font_tables[1]=&vga.draw.font[font2*8*1024];
00138                 }
00139                 /*
00140                         0,1,4  Selects VGA Character Map (0..7) if bit 3 of the character
00141                                         attribute is clear.
00142                         2,3,5  Selects VGA Character Map (0..7) if bit 3 of the character
00143                                         attribute is set.
00144                         Note: Character Maps are placed as follows:
00145                         Map 0 at 0k, 1 at 16k, 2 at 32k, 3: 48k, 4: 8k, 5: 24k, 6: 40k, 7: 56k
00146                 */
00147                 break;
00148         case 4: /* Memory Mode */
00149                 /* 
00150                         0  Set if in an alphanumeric mode, clear in graphics modes.
00151                         1  Set if more than 64kbytes on the adapter.
00152                         2  Enables Odd/Even addressing mode if set. Odd/Even mode places all odd
00153                                 bytes in plane 1&3, and all even bytes in plane 0&2.
00154                         3  If set address bit 0-1 selects video memory planes (256 color mode),
00155                                 rather than the Map Mask and Read Map Select Registers.
00156                 */
00157                 seq(memory_mode)=(Bit8u)val;
00158                 if (IS_VGA_ARCH) {
00159                         /* Changing this means changing the VGA Memory Read/Write Handler */
00160                         if (val&0x08) vga.config.chained=true;
00161                         else vga.config.chained=false;
00162                         VGA_SetupHandlers();
00163                 }
00164                 break;
00165         default:
00166                 if (svga.write_p3c5) {
00167                         svga.write_p3c5(seq(index), val, iolen);
00168                 } else {
00169                         LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:SEQ:Write to illegal index %2X",seq(index));
00170                 }
00171                 break;
00172         }
00173 }
00174 
00175 
00176 Bitu read_p3c5(Bitu /*port*/,Bitu iolen) {
00177 //      LOG_MSG("VGA:SEQ:Read from index %2X",seq(index));
00178         switch(seq(index)) {
00179         case 0:                 /* Reset */
00180                 return seq(reset);
00181                 break;
00182         case 1:                 /* Clocking Mode */
00183                 return seq(clocking_mode);
00184                 break;
00185         case 2:                 /* Map Mask */
00186                 return seq(map_mask);
00187                 break;
00188         case 3:                 /* Character Map Select */
00189                 return seq(character_map_select);
00190                 break;
00191         case 4:                 /* Memory Mode */
00192                 return seq(memory_mode);
00193                 break;
00194         default:
00195                 if (svga.read_p3c5)
00196                         return svga.read_p3c5(seq(index), iolen);
00197                 break;
00198         }
00199         return 0;
00200 }
00201 
00202 
00203 void VGA_SetupSEQ(void) {
00204         if (IS_EGAVGA_ARCH) {
00205                 IO_RegisterWriteHandler(0x3c4,write_p3c4,IO_MB);
00206                 IO_RegisterWriteHandler(0x3c5,write_p3c5,IO_MB);
00207                 if (IS_VGA_ARCH) {
00208                         IO_RegisterReadHandler(0x3c4,read_p3c4,IO_MB);
00209                         IO_RegisterReadHandler(0x3c5,read_p3c5,IO_MB);
00210                 }
00211         }
00212 }
00213 
00214 void VGA_UnsetupSEQ(void) {
00215     IO_FreeWriteHandler(0x3c4,IO_MB);
00216     IO_FreeReadHandler(0x3c4,IO_MB);
00217     IO_FreeWriteHandler(0x3c5,IO_MB);
00218     IO_FreeReadHandler(0x3c5,IO_MB);
00219 }
00220 
00221 // save state support
00222 void POD_Save_VGA_Seq( std::ostream& stream )
00223 {
00224         // - pure struct data
00225         WRITE_POD( &vga.seq, vga.seq );
00226 
00227 
00228         // no static globals found
00229 }
00230 
00231 
00232 void POD_Load_VGA_Seq( std::istream& stream )
00233 {
00234         // - pure struct data
00235         READ_POD( &vga.seq, vga.seq );
00236 
00237 
00238         // no static globals found
00239 }