DOSBox-X
|
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 "setup.h" 00022 #include "vga.h" 00023 #include "inout.h" 00024 #include "mem.h" 00025 00026 typedef struct SVGA_PVGA1A_DATA_t { 00027 Bitu PR0A; 00028 Bitu PR0B; 00029 Bitu PR1; 00030 Bitu PR2; 00031 Bitu PR3; 00032 Bitu PR4; 00033 Bitu PR5; 00034 00035 inline bool locked() { return (PR5&7)!=5; } 00036 00037 Bitu clockFreq[4]; 00038 Bitu biosMode; 00039 } SVGA_PVGA1A_DATA; 00040 00041 static SVGA_PVGA1A_DATA pvga1a = { 0,0, 0,0,0,0,0, {0,0,0,0}, 0 }; 00042 00043 00044 static void bank_setup_pvga1a() { 00045 // Note: There is some inconsistency in available documentation. Most sources tell that PVGA1A used 00046 // only 7 bits of bank index (VGADOC and Ferraro agree on that) but also point that there are 00047 // implementations with 1M of RAM which is simply not possible with 7-bit banks. This implementation 00048 // assumes that the eighth bit was actually wired and could be used. This does not conflict with 00049 // anything and actually works in WHATVGA just fine. 00050 if (pvga1a.PR1 & 0x08) { 00051 // TODO: Dual bank function is not supported yet 00052 // TODO: Requirements are not compatible with vga_memory implementation. 00053 } else { 00054 // Single bank config is straightforward 00055 vga.svga.bank_read = vga.svga.bank_write = (Bit8u)pvga1a.PR0A; 00056 vga.svga.bank_size = 4*1024; 00057 VGA_SetupHandlers(); 00058 } 00059 } 00060 00061 void write_p3cf_pvga1a(Bitu reg,Bitu val,Bitu iolen) { 00062 (void)iolen;//UNUSED 00063 if (pvga1a.locked() && reg >= 0x09 && reg <= 0x0e) 00064 return; 00065 00066 switch (reg) { 00067 case 0x09: 00068 // Bank A, 4K granularity, not using bit 7 00069 // Maps to A800h-AFFFh if PR1 bit 3 set and 64k config B000h-BFFFh if 128k config. A000h-AFFFh otherwise. 00070 pvga1a.PR0A = val; 00071 bank_setup_pvga1a(); 00072 break; 00073 case 0x0a: 00074 // Bank B, 4K granularity, not using bit 7 00075 // Maps to A000h-A7FFh if PR1 bit 3 set and 64k config, A000h-AFFFh if 128k 00076 pvga1a.PR0B = val; 00077 bank_setup_pvga1a(); 00078 break; 00079 case 0x0b: 00080 // Memory size. We only allow to mess with bit 3 here (enable bank B) - this may break some detection schemes 00081 pvga1a.PR1 = (pvga1a.PR1 & ~0x08u) | (val & 0x08u); 00082 bank_setup_pvga1a(); 00083 break; 00084 case 0x0c: 00085 // Video configuration 00086 // TODO: Figure out if there is anything worth implementing here. 00087 pvga1a.PR2 = val; 00088 break; 00089 case 0x0d: 00090 // CRT control. Bits 3-4 contain bits 16-17 of CRT start. 00091 // TODO: Implement bit 2 (CRT address doubling - this mechanism is present in other chipsets as well, 00092 // but not implemented in DosBox core) 00093 pvga1a.PR3 = val; 00094 vga.config.display_start = (vga.config.display_start & 0xffffu) | ((val & 0x18u)<<13u); 00095 vga.config.cursor_start = (vga.config.cursor_start & 0xffffu) | ((val & 0x18u)<<13u); 00096 break; 00097 case 0x0e: 00098 // Video control 00099 // TODO: Figure out if there is anything worth implementing here. 00100 pvga1a.PR4 = val; 00101 break; 00102 case 0x0f: 00103 // Enable extended registers 00104 pvga1a.PR5 = val; 00105 break; 00106 default: 00107 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:GFX:PVGA1A:Write to illegal index %2X", (int)reg); 00108 break; 00109 } 00110 } 00111 00112 Bitu read_p3cf_pvga1a(Bitu reg,Bitu iolen) { 00113 (void)iolen;//UNUSED 00114 if (pvga1a.locked() && reg >= 0x09 && reg <= 0x0e) 00115 return 0x0; 00116 00117 switch (reg) { 00118 case 0x09: 00119 return pvga1a.PR0A; 00120 case 0x0a: 00121 return pvga1a.PR0B; 00122 case 0x0b: 00123 return pvga1a.PR1; 00124 case 0x0c: 00125 return pvga1a.PR2; 00126 case 0x0d: 00127 return pvga1a.PR3; 00128 case 0x0e: 00129 return pvga1a.PR4; 00130 case 0x0f: 00131 return pvga1a.PR5; 00132 default: 00133 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:GFX:PVGA1A:Read from illegal index %2X", (int)reg); 00134 break; 00135 } 00136 00137 return 0x0; 00138 } 00139 00140 void FinishSetMode_PVGA1A(Bitu /*crtc_base*/, VGA_ModeExtraData* modeData) { 00141 pvga1a.biosMode = modeData->modeNo; 00142 00143 // Reset to single bank and set it to 0. May need to unlock first (DPaint locks on exit) 00144 IO_Write(0x3ce, 0x0f); 00145 Bitu oldlock = IO_Read(0x3cf); 00146 IO_Write(0x3cf, 0x05); 00147 IO_Write(0x3ce, 0x09); 00148 IO_Write(0x3cf, 0x00); 00149 IO_Write(0x3ce, 0x0a); 00150 IO_Write(0x3cf, 0x00); 00151 IO_Write(0x3ce, 0x0b); 00152 Bit8u val = IO_Read(0x3cf); 00153 IO_Write(0x3cf, val & ~0x08); 00154 IO_Write(0x3ce, 0x0c); 00155 IO_Write(0x3cf, 0x00); 00156 IO_Write(0x3ce, 0x0d); 00157 IO_Write(0x3cf, 0x00); 00158 IO_Write(0x3ce, 0x0e); 00159 IO_Write(0x3cf, 0x00); 00160 IO_Write(0x3ce, 0x0f); 00161 IO_Write(0x3cf, (Bit8u)oldlock); 00162 00163 if (svga.determine_mode) 00164 svga.determine_mode(); 00165 00166 if(vga.mode != M_VGA) { 00167 vga.config.compatible_chain4 = false; 00168 // vga.vmemwrap = vga.mem.memsize; 00169 } else { 00170 vga.config.compatible_chain4 = true; 00171 // vga.vmemwrap = 256*1024; 00172 } 00173 00174 VGA_SetupHandlers(); 00175 } 00176 00177 void DetermineMode_PVGA1A() { 00178 // Close replica from the base implementation. It will stay here 00179 // until I figure a way to either distinguish M_VGA and M_LIN8 or 00180 // merge them. 00181 if (vga.attr.mode_control & 1) { 00182 if (vga.gfx.mode & 0x40) VGA_SetMode((pvga1a.biosMode<=0x13)?M_VGA:M_LIN8); 00183 else if (vga.gfx.mode & 0x20) VGA_SetMode(M_CGA4); 00184 else if ((vga.gfx.miscellaneous & 0x0c)==0x0c) VGA_SetMode(M_CGA2); 00185 else VGA_SetMode((pvga1a.biosMode<=0x13)?M_EGA:M_LIN4); 00186 } else { 00187 VGA_SetMode(M_TEXT); 00188 } 00189 } 00190 00191 void SetClock_PVGA1A(Bitu which,Bitu target) { 00192 if (which < 4) { 00193 pvga1a.clockFreq[which]=1000*target; 00194 VGA_StartResize(); 00195 } 00196 } 00197 00198 Bitu GetClock_PVGA1A() { 00199 return pvga1a.clockFreq[(vga.misc_output >> 2) & 3]; 00200 } 00201 00202 bool AcceptsMode_PVGA1A(Bitu mode) { 00203 return VideoModeMemSize(mode) < vga.mem.memsize; 00204 } 00205 00206 void SVGA_Setup_ParadisePVGA1A(void) { 00207 svga.write_p3cf = &write_p3cf_pvga1a; 00208 svga.read_p3cf = &read_p3cf_pvga1a; 00209 00210 svga.set_video_mode = &FinishSetMode_PVGA1A; 00211 svga.determine_mode = &DetermineMode_PVGA1A; 00212 svga.set_clock = &SetClock_PVGA1A; 00213 svga.get_clock = &GetClock_PVGA1A; 00214 svga.accepts_mode = &AcceptsMode_PVGA1A; 00215 00216 VGA_SetClock(0,CLK_25); 00217 VGA_SetClock(1,CLK_28); 00218 VGA_SetClock(2,32400); // could not find documentation 00219 VGA_SetClock(3,35900); 00220 00221 // Adjust memory, default to 512K 00222 if (vga.mem.memsize == 0) 00223 vga.mem.memsize = 512*1024; 00224 00225 if (vga.mem.memsize < 512*1024) { 00226 vga.mem.memsize = 256*1024; 00227 pvga1a.PR1 = 1<<6; 00228 } else if (vga.mem.memsize > 512*1024) { 00229 vga.mem.memsize = 1024*1024; 00230 pvga1a.PR1 = 3<<6; 00231 } else { 00232 pvga1a.PR1 = 2<<6; 00233 } 00234 00235 // Paradise ROM signature 00236 PhysPt rom_base=PhysMake(0xc000,0); 00237 phys_writeb(rom_base+0x007d,'V'); 00238 phys_writeb(rom_base+0x007e,'G'); 00239 phys_writeb(rom_base+0x007f,'A'); 00240 phys_writeb(rom_base+0x0080,'='); 00241 00242 IO_Write(0x3cf, 0x05); // Enable! 00243 } 00244 00245 // save state support 00246 void POD_Save_VGA_Paradise( std::ostream& stream ) 00247 { 00248 // static globals 00249 00250 00251 // - pure struct data 00252 WRITE_POD( &pvga1a, pvga1a ); 00253 } 00254 00255 00256 void POD_Load_VGA_Paradise( std::istream& stream ) 00257 { 00258 // static globals 00259 00260 00261 // - pure struct data 00262 READ_POD( &pvga1a, pvga1a ); 00263 }