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