DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/vga_paradise.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 "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 }