1 /*
2 * Copyright (C) 2002-2010 The DOSBox Team
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 /* $Id: vga_paradise.cpp,v 1.4 2009-05-27 09:15:41 qbix79 Exp $ */
20
21 #include "dosbox.h"
22 #include "setup.h"
23 #include "vga.h"
24 #include "inout.h"
25 #include "mem.h"
26
27 typedef struct {
28 Bitu PR0A;
29 Bitu PR0B;
30 Bitu PR1;
31 Bitu PR2;
32 Bitu PR3;
33 Bitu PR4;
34 Bitu PR5;
35
locked__anonefed7ab2010836 inline bool locked() { return (PR5&7)!=5; }
37
38 Bitu clockFreq[4];
39 Bitu biosMode;
40 } SVGA_PVGA1A_DATA;
41
42 static SVGA_PVGA1A_DATA pvga1a = { 0,0, 0,0,0,0,0, {0,0,0,0}, 0 };
43
44
bank_setup_pvga1a()45 static void bank_setup_pvga1a() {
46 // Note: There is some inconsistency in available documentation. Most sources tell that PVGA1A used
47 // only 7 bits of bank index (VGADOC and Ferraro agree on that) but also point that there are
48 // implementations with 1M of RAM which is simply not possible with 7-bit banks. This implementation
49 // assumes that the eighth bit was actually wired and could be used. This does not conflict with
50 // anything and actually works in WHATVGA just fine.
51 if (pvga1a.PR1 & 0x08) {
52 // TODO: Dual bank function is not supported yet
53 // TODO: Requirements are not compatible with vga_memory implementation.
54 } else {
55 // Single bank config is straightforward
56 vga.svga.bank_read = vga.svga.bank_write = pvga1a.PR0A;
57 vga.svga.bank_size = 4*1024;
58 VGA_SetupHandlers();
59 }
60 }
61
write_p3cf_pvga1a(Bitu reg,Bitu val,Bitu iolen)62 void write_p3cf_pvga1a(Bitu reg,Bitu val,Bitu iolen) {
63 if (pvga1a.locked() && reg >= 0x09 && reg <= 0x0e)
64 return;
65
66 switch (reg) {
67 case 0x09:
68 // Bank A, 4K granularity, not using bit 7
69 // Maps to A800h-AFFFh if PR1 bit 3 set and 64k config B000h-BFFFh if 128k config. A000h-AFFFh otherwise.
70 pvga1a.PR0A = val;
71 bank_setup_pvga1a();
72 break;
73 case 0x0a:
74 // Bank B, 4K granularity, not using bit 7
75 // Maps to A000h-A7FFh if PR1 bit 3 set and 64k config, A000h-AFFFh if 128k
76 pvga1a.PR0B = val;
77 bank_setup_pvga1a();
78 break;
79 case 0x0b:
80 // Memory size. We only allow to mess with bit 3 here (enable bank B) - this may break some detection schemes
81 pvga1a.PR1 = (pvga1a.PR1 & ~0x08) | (val & 0x08);
82 bank_setup_pvga1a();
83 break;
84 case 0x0c:
85 // Video configuration
86 // TODO: Figure out if there is anything worth implementing here.
87 pvga1a.PR2 = val;
88 break;
89 case 0x0d:
90 // CRT control. Bits 3-4 contain bits 16-17 of CRT start.
91 // TODO: Implement bit 2 (CRT address doubling - this mechanism is present in other chipsets as well,
92 // but not implemented in DosBox core)
93 pvga1a.PR3 = val;
94 vga.config.display_start = (vga.config.display_start & 0xffff) | ((val & 0x18)<<13);
95 vga.config.cursor_start = (vga.config.cursor_start & 0xffff) | ((val & 0x18)<<13);
96 break;
97 case 0x0e:
98 // Video control
99 // TODO: Figure out if there is anything worth implementing here.
100 pvga1a.PR4 = val;
101 break;
102 case 0x0f:
103 // Enable extended registers
104 pvga1a.PR5 = val;
105 break;
106 default:
107 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:GFX:PVGA1A:Write to illegal index %2X", reg);
108 break;
109 }
110 }
111
read_p3cf_pvga1a(Bitu reg,Bitu iolen)112 Bitu read_p3cf_pvga1a(Bitu reg,Bitu iolen) {
113 if (pvga1a.locked() && reg >= 0x09 && reg <= 0x0e)
114 return 0x0;
115
116 switch (reg) {
117 case 0x09:
118 return pvga1a.PR0A;
119 case 0x0a:
120 return pvga1a.PR0B;
121 case 0x0b:
122 return pvga1a.PR1;
123 case 0x0c:
124 return pvga1a.PR2;
125 case 0x0d:
126 return pvga1a.PR3;
127 case 0x0e:
128 return pvga1a.PR4;
129 case 0x0f:
130 return pvga1a.PR5;
131 default:
132 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:GFX:PVGA1A:Read from illegal index %2X", reg);
133 break;
134 }
135
136 return 0x0;
137 }
138
FinishSetMode_PVGA1A(Bitu,VGA_ModeExtraData * modeData)139 void FinishSetMode_PVGA1A(Bitu /*crtc_base*/, VGA_ModeExtraData* modeData) {
140 pvga1a.biosMode = modeData->modeNo;
141
142 // Reset to single bank and set it to 0. May need to unlock first (DPaint locks on exit)
143 IO_Write(0x3ce, 0x0f);
144 Bitu oldlock = IO_Read(0x3cf);
145 IO_Write(0x3cf, 0x05);
146 IO_Write(0x3ce, 0x09);
147 IO_Write(0x3cf, 0x00);
148 IO_Write(0x3ce, 0x0a);
149 IO_Write(0x3cf, 0x00);
150 IO_Write(0x3ce, 0x0b);
151 Bit8u val = IO_Read(0x3cf);
152 IO_Write(0x3cf, val & ~0x08);
153 IO_Write(0x3ce, 0x0c);
154 IO_Write(0x3cf, 0x00);
155 IO_Write(0x3ce, 0x0d);
156 IO_Write(0x3cf, 0x00);
157 IO_Write(0x3ce, 0x0e);
158 IO_Write(0x3cf, 0x00);
159 IO_Write(0x3ce, 0x0f);
160 IO_Write(0x3cf, oldlock);
161
162 if (svga.determine_mode)
163 svga.determine_mode();
164
165 if(vga.mode != M_VGA) {
166 vga.config.compatible_chain4 = false;
167 vga.vmemwrap = vga.vmemsize;
168 } else {
169 vga.config.compatible_chain4 = true;
170 vga.vmemwrap = 256*1024;
171 }
172
173 VGA_SetupHandlers();
174 }
175
DetermineMode_PVGA1A()176 void DetermineMode_PVGA1A() {
177 // Close replica from the base implementation. It will stay here
178 // until I figure a way to either distinguish M_VGA and M_LIN8 or
179 // merge them.
180 if (vga.attr.mode_control & 1) {
181 if (vga.gfx.mode & 0x40) VGA_SetMode((pvga1a.biosMode<=0x13)?M_VGA:M_LIN8);
182 else if (vga.gfx.mode & 0x20) VGA_SetMode(M_CGA4);
183 else if ((vga.gfx.miscellaneous & 0x0c)==0x0c) VGA_SetMode(M_CGA2);
184 else VGA_SetMode((pvga1a.biosMode<=0x13)?M_EGA:M_LIN4);
185 } else {
186 VGA_SetMode(M_TEXT);
187 }
188 }
189
SetClock_PVGA1A(Bitu which,Bitu target)190 void SetClock_PVGA1A(Bitu which,Bitu target) {
191 if (which < 4) {
192 pvga1a.clockFreq[which]=1000*target;
193 VGA_StartResize();
194 }
195 }
196
GetClock_PVGA1A()197 Bitu GetClock_PVGA1A() {
198 return pvga1a.clockFreq[(vga.misc_output >> 2) & 3];
199 }
200
AcceptsMode_PVGA1A(Bitu mode)201 bool AcceptsMode_PVGA1A(Bitu mode) {
202 return VideoModeMemSize(mode) < vga.vmemsize;
203 }
204
SVGA_Setup_ParadisePVGA1A(void)205 void SVGA_Setup_ParadisePVGA1A(void) {
206 svga.write_p3cf = &write_p3cf_pvga1a;
207 svga.read_p3cf = &read_p3cf_pvga1a;
208
209 svga.set_video_mode = &FinishSetMode_PVGA1A;
210 svga.determine_mode = &DetermineMode_PVGA1A;
211 svga.set_clock = &SetClock_PVGA1A;
212 svga.get_clock = &GetClock_PVGA1A;
213 svga.accepts_mode = &AcceptsMode_PVGA1A;
214
215 VGA_SetClock(0,CLK_25);
216 VGA_SetClock(1,CLK_28);
217 VGA_SetClock(2,32400); // could not find documentation
218 VGA_SetClock(3,35900);
219
220 // Adjust memory, default to 512K
221 if (vga.vmemsize == 0)
222 vga.vmemsize = 512*1024;
223
224 if (vga.vmemsize < 512*1024) {
225 vga.vmemsize = 256*1024;
226 pvga1a.PR1 = 1<<6;
227 } else if (vga.vmemsize > 512*1024) {
228 vga.vmemsize = 1024*1024;
229 pvga1a.PR1 = 3<<6;
230 } else {
231 pvga1a.PR1 = 2<<6;
232 }
233
234 // Paradise ROM signature
235 PhysPt rom_base=PhysMake(0xc000,0);
236 phys_writeb(rom_base+0x007d,'V');
237 phys_writeb(rom_base+0x007e,'G');
238 phys_writeb(rom_base+0x007f,'A');
239 phys_writeb(rom_base+0x0080,'=');
240
241 IO_Write(0x3cf, 0x05); // Enable!
242 }
243