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_memory.cpp,v 1.53 2009-07-04 21:23:35 qbix79 Exp $ */
20 
21 #include <stdlib.h>
22 #include <string.h>
23 #include "dosbox.h"
24 #include "mem.h"
25 #include "vga.h"
26 #include "paging.h"
27 #include "pic.h"
28 #include "inout.h"
29 #include "setup.h"
30 
31 
32 #ifndef C_VGARAM_CHECKED
33 #define C_VGARAM_CHECKED 1
34 #endif
35 
36 #if C_VGARAM_CHECKED
37 // Checked linear offset
38 #define CHECKED(v) ((v)&(vga.vmemwrap-1))
39 // Checked planar offset (latched access)
40 #define CHECKED2(v) ((v)&((vga.vmemwrap>>2)-1))
41 #else
42 #define CHECKED(v) (v)
43 #define CHECKED2(v) (v)
44 #endif
45 
46 #define CHECKED3(v) ((v)&(vga.vmemwrap-1))
47 #define CHECKED4(v) ((v)&((vga.vmemwrap>>2)-1))
48 
49 
50 #ifdef VGA_KEEP_CHANGES
51 #define MEM_CHANGED( _MEM ) vga.changes.map[ (_MEM) >> VGA_CHANGE_SHIFT ] |= vga.changes.writeMask;
52 //#define MEM_CHANGED( _MEM ) vga.changes.map[ (_MEM) >> VGA_CHANGE_SHIFT ] = 1;
53 #else
54 #define MEM_CHANGED( _MEM )
55 #endif
56 
57 #define TANDY_VIDBASE(_X_)  &MemBase[ 0x80000 + (_X_)]
58 
59 template <class Size>
hostWrite(HostPt off,Bitu val)60 static INLINE void hostWrite(HostPt off, Bitu val) {
61 	if ( sizeof( Size ) == 1)
62 		host_writeb( off, (Bit8u)val );
63 	else if ( sizeof( Size ) == 2)
64 		host_writew( off, (Bit16u)val );
65 	else if ( sizeof( Size ) == 4)
66 		host_writed( off, (Bit32u)val );
67 }
68 
69 template <class Size>
hostRead(HostPt off)70 static INLINE Bitu  hostRead(HostPt off ) {
71 	if ( sizeof( Size ) == 1)
72 		return host_readb( off );
73 	else if ( sizeof( Size ) == 2)
74 		return host_readw( off );
75 	else if ( sizeof( Size ) == 4)
76 		return host_readd( off );
77 	return 0;
78 }
79 
80 
81 void VGA_MapMMIO(void);
82 //Nice one from DosEmu
RasterOp(Bit32u input,Bit32u mask)83 INLINE static Bit32u RasterOp(Bit32u input,Bit32u mask) {
84 	switch (vga.config.raster_op) {
85 	case 0x00:	/* None */
86 		return (input & mask) | (vga.latch.d & ~mask);
87 	case 0x01:	/* AND */
88 		return (input | ~mask) & vga.latch.d;
89 	case 0x02:	/* OR */
90 		return (input & mask) | vga.latch.d;
91 	case 0x03:	/* XOR */
92 		return (input & mask) ^ vga.latch.d;
93 	};
94 	return 0;
95 }
96 
ModeOperation(Bit8u val)97 INLINE static Bit32u ModeOperation(Bit8u val) {
98 	Bit32u full;
99 	switch (vga.config.write_mode) {
100 	case 0x00:
101 		// Write Mode 0: In this mode, the host data is first rotated as per the Rotate Count field, then the Enable Set/Reset mechanism selects data from this or the Set/Reset field. Then the selected Logical Operation is performed on the resulting data and the data in the latch register. Then the Bit Mask field is used to select which bits come from the resulting data and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory.
102 		val=((val >> vga.config.data_rotate) | (val << (8-vga.config.data_rotate)));
103 		full=ExpandTable[val];
104 		full=(full & vga.config.full_not_enable_set_reset) | vga.config.full_enable_and_set_reset;
105 		full=RasterOp(full,vga.config.full_bit_mask);
106 		break;
107 	case 0x01:
108 		// Write Mode 1: In this mode, data is transferred directly from the 32 bit latch register to display memory, affected only by the Memory Plane Write Enable field. The host data is not used in this mode.
109 		full=vga.latch.d;
110 		break;
111 	case 0x02:
112 		//Write Mode 2: In this mode, the bits 3-0 of the host data are replicated across all 8 bits of their respective planes. Then the selected Logical Operation is performed on the resulting data and the data in the latch register. Then the Bit Mask field is used to select which bits come from the resulting data and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory.
113 		full=RasterOp(FillTable[val&0xF],vga.config.full_bit_mask);
114 		break;
115 	case 0x03:
116 		// Write Mode 3: In this mode, the data in the Set/Reset field is used as if the Enable Set/Reset field were set to 1111b. Then the host data is first rotated as per the Rotate Count field, then logical ANDed with the value of the Bit Mask field. The resulting value is used on the data obtained from the Set/Reset field in the same way that the Bit Mask field would ordinarily be used. to select which bits come from the expansion of the Set/Reset field and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory.
117 		val=((val >> vga.config.data_rotate) | (val << (8-vga.config.data_rotate)));
118 		full=RasterOp(vga.config.full_set_reset,ExpandTable[val] & vga.config.full_bit_mask);
119 		break;
120 	default:
121 		LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:Unsupported write mode %d",vga.config.write_mode);
122 		full=0;
123 		break;
124 	}
125 	return full;
126 }
127 
128 /* Gonna assume that whoever maps vga memory, maps it on 32/64kb boundary */
129 
130 #define VGA_PAGES		(128/4)
131 #define VGA_PAGE_A0		(0xA0000/4096)
132 #define VGA_PAGE_B0		(0xB0000/4096)
133 #define VGA_PAGE_B8		(0xB8000/4096)
134 
135 static struct {
136 	Bitu base, mask;
137 } vgapages;
138 
139 class VGA_UnchainedRead_Handler : public PageHandler {
140 public:
readHandler(PhysPt start)141 	Bitu readHandler(PhysPt start) {
142 		vga.latch.d=((Bit32u*)vga.mem.linear)[start];
143 		switch (vga.config.read_mode) {
144 		case 0:
145 			return (vga.latch.b[vga.config.read_map_select]);
146 		case 1:
147 			VGA_Latch templatch;
148 			templatch.d=(vga.latch.d &	FillTable[vga.config.color_dont_care]) ^ FillTable[vga.config.color_compare & vga.config.color_dont_care];
149 			return (Bit8u)~(templatch.b[0] | templatch.b[1] | templatch.b[2] | templatch.b[3]);
150 		}
151 		return 0;
152 	}
153 public:
readb(PhysPt addr)154 	Bitu readb(PhysPt addr) {
155 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
156 		addr += vga.svga.bank_read_full;
157 		addr = CHECKED2(addr);
158 		return readHandler(addr);
159 	}
readw(PhysPt addr)160 	Bitu readw(PhysPt addr) {
161 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
162 		addr += vga.svga.bank_read_full;
163 		addr = CHECKED2(addr);
164 		Bitu ret = (readHandler(addr+0) << 0);
165 		ret     |= (readHandler(addr+1) << 8);
166 		return  ret;
167 	}
readd(PhysPt addr)168 	Bitu readd(PhysPt addr) {
169 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
170 		addr += vga.svga.bank_read_full;
171 		addr = CHECKED2(addr);
172 		Bitu ret = (readHandler(addr+0) << 0);
173 		ret     |= (readHandler(addr+1) << 8);
174 		ret     |= (readHandler(addr+2) << 16);
175 		ret     |= (readHandler(addr+3) << 24);
176 		return ret;
177 	}
178 };
179 
180 class VGA_ChainedEGA_Handler : public PageHandler {
181 public:
readHandler(PhysPt addr)182 	Bitu readHandler(PhysPt addr) {
183 		return vga.mem.linear[addr];
184 	}
writeHandler(PhysPt start,Bit8u val)185 	void writeHandler(PhysPt start, Bit8u val) {
186 		ModeOperation(val);
187 		/* Update video memory and the pixel buffer */
188 		VGA_Latch pixels;
189 		vga.mem.linear[start] = val;
190 		start >>= 2;
191 		pixels.d=((Bit32u*)vga.mem.linear)[start];
192 
193 		Bit8u * write_pixels=&vga.fastmem[start<<3];
194 
195 		Bit32u colors0_3, colors4_7;
196 		VGA_Latch temp;temp.d=(pixels.d>>4) & 0x0f0f0f0f;
197 		colors0_3 =
198 			Expand16Table[0][temp.b[0]] |
199 			Expand16Table[1][temp.b[1]] |
200 			Expand16Table[2][temp.b[2]] |
201 			Expand16Table[3][temp.b[3]];
202 		*(Bit32u *)write_pixels=colors0_3;
203 		temp.d=pixels.d & 0x0f0f0f0f;
204 		colors4_7 =
205 			Expand16Table[0][temp.b[0]] |
206 			Expand16Table[1][temp.b[1]] |
207 			Expand16Table[2][temp.b[2]] |
208 			Expand16Table[3][temp.b[3]];
209 		*(Bit32u *)(write_pixels+4)=colors4_7;
210 	}
211 public:
VGA_ChainedEGA_Handler()212 	VGA_ChainedEGA_Handler()  {
213 		flags=PFLAG_NOCODE;
214 	}
writeb(PhysPt addr,Bitu val)215 	void writeb(PhysPt addr,Bitu val) {
216 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
217 		addr += vga.svga.bank_write_full;
218 		addr = CHECKED(addr);
219 		MEM_CHANGED( addr << 3);
220 		writeHandler(addr+0,(Bit8u)(val >> 0));
221 	}
writew(PhysPt addr,Bitu val)222 	void writew(PhysPt addr,Bitu val) {
223 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
224 		addr += vga.svga.bank_write_full;
225 		addr = CHECKED(addr);
226 		MEM_CHANGED( addr << 3);
227 		writeHandler(addr+0,(Bit8u)(val >> 0));
228 		writeHandler(addr+1,(Bit8u)(val >> 8));
229 	}
writed(PhysPt addr,Bitu val)230 	void writed(PhysPt addr,Bitu val) {
231 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
232 		addr += vga.svga.bank_write_full;
233 		addr = CHECKED(addr);
234 		MEM_CHANGED( addr << 3);
235 		writeHandler(addr+0,(Bit8u)(val >> 0));
236 		writeHandler(addr+1,(Bit8u)(val >> 8));
237 		writeHandler(addr+2,(Bit8u)(val >> 16));
238 		writeHandler(addr+3,(Bit8u)(val >> 24));
239 	}
readb(PhysPt addr)240 	Bitu readb(PhysPt addr) {
241 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
242 		addr += vga.svga.bank_read_full;
243 		addr = CHECKED(addr);
244 		return readHandler(addr);
245 	}
readw(PhysPt addr)246 	Bitu readw(PhysPt addr) {
247 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
248 		addr += vga.svga.bank_read_full;
249 		addr = CHECKED(addr);
250 		Bitu ret = (readHandler(addr+0) << 0);
251 		ret     |= (readHandler(addr+1) << 8);
252 		return ret;
253 	}
readd(PhysPt addr)254 	Bitu readd(PhysPt addr) {
255 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
256 		addr += vga.svga.bank_read_full;
257 		addr = CHECKED(addr);
258 		Bitu ret = (readHandler(addr+0) << 0);
259 		ret     |= (readHandler(addr+1) << 8);
260 		ret     |= (readHandler(addr+2) << 16);
261 		ret     |= (readHandler(addr+3) << 24);
262 		return ret;
263 	}
264 };
265 
266 class VGA_UnchainedEGA_Handler : public VGA_UnchainedRead_Handler {
267 public:
268 	template< bool wrapping>
writeHandler(PhysPt start,Bit8u val)269 	void writeHandler(PhysPt start, Bit8u val) {
270 		Bit32u data=ModeOperation(val);
271 		/* Update video memory and the pixel buffer */
272 		VGA_Latch pixels;
273 		pixels.d=((Bit32u*)vga.mem.linear)[start];
274 		pixels.d&=vga.config.full_not_map_mask;
275 		pixels.d|=(data & vga.config.full_map_mask);
276 		((Bit32u*)vga.mem.linear)[start]=pixels.d;
277 		Bit8u * write_pixels=&vga.fastmem[start<<3];
278 
279 		Bit32u colors0_3, colors4_7;
280 		VGA_Latch temp;temp.d=(pixels.d>>4) & 0x0f0f0f0f;
281 			colors0_3 =
282 			Expand16Table[0][temp.b[0]] |
283 			Expand16Table[1][temp.b[1]] |
284 			Expand16Table[2][temp.b[2]] |
285 			Expand16Table[3][temp.b[3]];
286 		*(Bit32u *)write_pixels=colors0_3;
287 		temp.d=pixels.d & 0x0f0f0f0f;
288 		colors4_7 =
289 			Expand16Table[0][temp.b[0]] |
290 			Expand16Table[1][temp.b[1]] |
291 			Expand16Table[2][temp.b[2]] |
292 			Expand16Table[3][temp.b[3]];
293 		*(Bit32u *)(write_pixels+4)=colors4_7;
294 	}
295 public:
VGA_UnchainedEGA_Handler()296 	VGA_UnchainedEGA_Handler()  {
297 		flags=PFLAG_NOCODE;
298 	}
writeb(PhysPt addr,Bitu val)299 	void writeb(PhysPt addr,Bitu val) {
300 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
301 		addr += vga.svga.bank_write_full;
302 		addr = CHECKED2(addr);
303 		MEM_CHANGED( addr << 3);
304 		writeHandler<true>(addr+0,(Bit8u)(val >> 0));
305 	}
writew(PhysPt addr,Bitu val)306 	void writew(PhysPt addr,Bitu val) {
307 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
308 		addr += vga.svga.bank_write_full;
309 		addr = CHECKED2(addr);
310 		MEM_CHANGED( addr << 3);
311 		writeHandler<true>(addr+0,(Bit8u)(val >> 0));
312 		writeHandler<true>(addr+1,(Bit8u)(val >> 8));
313 	}
writed(PhysPt addr,Bitu val)314 	void writed(PhysPt addr,Bitu val) {
315 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
316 		addr += vga.svga.bank_write_full;
317 		addr = CHECKED2(addr);
318 		MEM_CHANGED( addr << 3);
319 		writeHandler<true>(addr+0,(Bit8u)(val >> 0));
320 		writeHandler<true>(addr+1,(Bit8u)(val >> 8));
321 		writeHandler<true>(addr+2,(Bit8u)(val >> 16));
322 		writeHandler<true>(addr+3,(Bit8u)(val >> 24));
323 	}
324 };
325 
326 //Slighly unusual version, will directly write 8,16,32 bits values
327 class VGA_ChainedVGA_Handler : public PageHandler {
328 public:
VGA_ChainedVGA_Handler()329 	VGA_ChainedVGA_Handler()  {
330 		flags=PFLAG_NOCODE;
331 	}
332 	template <class Size>
readHandler(PhysPt addr)333 	static INLINE Bitu readHandler(PhysPt addr ) {
334 		return hostRead<Size>( &vga.mem.linear[((addr&~3)<<2)+(addr&3)] );
335 	}
336 	template <class Size>
writeCache(PhysPt addr,Bitu val)337 	static INLINE void writeCache(PhysPt addr, Bitu val) {
338 		hostWrite<Size>( &vga.fastmem[addr], val );
339 		if (GCC_UNLIKELY(addr < 320)) {
340 			// And replicate the first line
341 			hostWrite<Size>( &vga.fastmem[addr+64*1024], val );
342 		}
343 	}
344 	template <class Size>
writeHandler(PhysPt addr,Bitu val)345 	static INLINE void writeHandler(PhysPt addr, Bitu val) {
346 		// No need to check for compatible chains here, this one is only enabled if that bit is set
347 		hostWrite<Size>( &vga.mem.linear[((addr&~3)<<2)+(addr&3)], val );
348 	}
readb(PhysPt addr)349 	Bitu readb(PhysPt addr ) {
350 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
351 		addr += vga.svga.bank_read_full;
352 		addr = CHECKED(addr);
353 		return readHandler<Bit8u>( addr );
354 	}
readw(PhysPt addr)355 	Bitu readw(PhysPt addr ) {
356 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
357 		addr += vga.svga.bank_read_full;
358 		addr = CHECKED(addr);
359 		if (GCC_UNLIKELY(addr & 1)) {
360 			Bitu ret = (readHandler<Bit8u>( addr+0 ) << 0 );
361 			ret     |= (readHandler<Bit8u>( addr+1 ) << 8 );
362 			return ret;
363 		} else
364 			return readHandler<Bit16u>( addr );
365 	}
readd(PhysPt addr)366 	Bitu readd(PhysPt addr ) {
367 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
368 		addr += vga.svga.bank_read_full;
369 		addr = CHECKED(addr);
370 		if (GCC_UNLIKELY(addr & 3)) {
371 			Bitu ret = (readHandler<Bit8u>( addr+0 ) << 0 );
372 			ret     |= (readHandler<Bit8u>( addr+1 ) << 8 );
373 			ret     |= (readHandler<Bit8u>( addr+2 ) << 16 );
374 			ret     |= (readHandler<Bit8u>( addr+3 ) << 24 );
375 			return ret;
376 		} else
377 			return readHandler<Bit32u>( addr );
378 	}
writeb(PhysPt addr,Bitu val)379 	void writeb(PhysPt addr, Bitu val ) {
380 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
381 		addr += vga.svga.bank_write_full;
382 		addr = CHECKED(addr);
383 		MEM_CHANGED( addr );
384 		writeHandler<Bit8u>( addr, val );
385 		writeCache<Bit8u>( addr, val );
386 	}
writew(PhysPt addr,Bitu val)387 	void writew(PhysPt addr,Bitu val) {
388 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
389 		addr += vga.svga.bank_write_full;
390 		addr = CHECKED(addr);
391 		MEM_CHANGED( addr );
392 //		MEM_CHANGED( addr + 1);
393 		if (GCC_UNLIKELY(addr & 1)) {
394 			writeHandler<Bit8u>( addr+0, val >> 0 );
395 			writeHandler<Bit8u>( addr+1, val >> 8 );
396 		} else {
397 			writeHandler<Bit16u>( addr, val );
398 		}
399 		writeCache<Bit16u>( addr, val );
400 	}
writed(PhysPt addr,Bitu val)401 	void writed(PhysPt addr,Bitu val) {
402 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
403 		addr += vga.svga.bank_write_full;
404 		addr = CHECKED(addr);
405 		MEM_CHANGED( addr );
406 //		MEM_CHANGED( addr + 3);
407 		if (GCC_UNLIKELY(addr & 3)) {
408 			writeHandler<Bit8u>( addr+0, val >> 0 );
409 			writeHandler<Bit8u>( addr+1, val >> 8 );
410 			writeHandler<Bit8u>( addr+2, val >> 16 );
411 			writeHandler<Bit8u>( addr+3, val >> 24 );
412 		} else {
413 			writeHandler<Bit32u>( addr, val );
414 		}
415 		writeCache<Bit32u>( addr, val );
416 	}
417 };
418 
419 class VGA_UnchainedVGA_Handler : public VGA_UnchainedRead_Handler {
420 public:
writeHandler(PhysPt addr,Bit8u val)421 	void writeHandler( PhysPt addr, Bit8u val ) {
422 		Bit32u data=ModeOperation(val);
423 		VGA_Latch pixels;
424 		pixels.d=((Bit32u*)vga.mem.linear)[addr];
425 		pixels.d&=vga.config.full_not_map_mask;
426 		pixels.d|=(data & vga.config.full_map_mask);
427 		((Bit32u*)vga.mem.linear)[addr]=pixels.d;
428 //		if(vga.config.compatible_chain4)
429 //			((Bit32u*)vga.mem.linear)[CHECKED2(addr+64*1024)]=pixels.d;
430 	}
431 public:
VGA_UnchainedVGA_Handler()432 	VGA_UnchainedVGA_Handler()  {
433 		flags=PFLAG_NOCODE;
434 	}
writeb(PhysPt addr,Bitu val)435 	void writeb(PhysPt addr,Bitu val) {
436 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
437 		addr += vga.svga.bank_write_full;
438 		addr = CHECKED2(addr);
439 		MEM_CHANGED( addr << 2 );
440 		writeHandler(addr+0,(Bit8u)(val >> 0));
441 	}
writew(PhysPt addr,Bitu val)442 	void writew(PhysPt addr,Bitu val) {
443 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
444 		addr += vga.svga.bank_write_full;
445 		addr = CHECKED2(addr);
446 		MEM_CHANGED( addr << 2);
447 		writeHandler(addr+0,(Bit8u)(val >> 0));
448 		writeHandler(addr+1,(Bit8u)(val >> 8));
449 	}
writed(PhysPt addr,Bitu val)450 	void writed(PhysPt addr,Bitu val) {
451 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
452 		addr += vga.svga.bank_write_full;
453 		addr = CHECKED2(addr);
454 		MEM_CHANGED( addr << 2);
455 		writeHandler(addr+0,(Bit8u)(val >> 0));
456 		writeHandler(addr+1,(Bit8u)(val >> 8));
457 		writeHandler(addr+2,(Bit8u)(val >> 16));
458 		writeHandler(addr+3,(Bit8u)(val >> 24));
459 	}
460 };
461 
462 class VGA_TEXT_PageHandler : public PageHandler {
463 public:
VGA_TEXT_PageHandler()464 	VGA_TEXT_PageHandler() {
465 		flags=PFLAG_NOCODE;
466 	}
readb(PhysPt addr)467 	Bitu readb(PhysPt addr) {
468 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
469 		return vga.draw.font[addr];
470 	}
writeb(PhysPt addr,Bitu val)471 	void writeb(PhysPt addr,Bitu val){
472 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
473 		if (vga.seq.map_mask & 0x4) {
474 			vga.draw.font[addr]=(Bit8u)val;
475 		}
476 	}
477 };
478 
479 class VGA_Map_Handler : public PageHandler {
480 public:
VGA_Map_Handler()481 	VGA_Map_Handler() {
482 		flags=PFLAG_READABLE|PFLAG_WRITEABLE|PFLAG_NOCODE;
483 	}
GetHostReadPt(Bitu phys_page)484 	HostPt GetHostReadPt(Bitu phys_page) {
485  		phys_page-=vgapages.base;
486 		return &vga.mem.linear[CHECKED3(vga.svga.bank_read_full+phys_page*4096)];
487 	}
GetHostWritePt(Bitu phys_page)488 	HostPt GetHostWritePt(Bitu phys_page) {
489  		phys_page-=vgapages.base;
490 		return &vga.mem.linear[CHECKED3(vga.svga.bank_write_full+phys_page*4096)];
491 	}
492 };
493 
494 class VGA_Changes_Handler : public PageHandler {
495 public:
VGA_Changes_Handler()496 	VGA_Changes_Handler() {
497 		flags=PFLAG_NOCODE;
498 	}
readb(PhysPt addr)499 	Bitu readb(PhysPt addr) {
500 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
501 		addr += vga.svga.bank_read_full;
502 		addr = CHECKED(addr);
503 		return hostRead<Bit8u>( &vga.mem.linear[addr] );
504 	}
readw(PhysPt addr)505 	Bitu readw(PhysPt addr) {
506 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
507 		addr += vga.svga.bank_read_full;
508 		addr = CHECKED(addr);
509 		return hostRead<Bit16u>( &vga.mem.linear[addr] );
510 	}
readd(PhysPt addr)511 	Bitu readd(PhysPt addr) {
512 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
513 		addr += vga.svga.bank_read_full;
514 		addr = CHECKED(addr);
515 		return hostRead<Bit32u>( &vga.mem.linear[addr] );
516 	}
writeb(PhysPt addr,Bitu val)517 	void writeb(PhysPt addr,Bitu val) {
518 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
519 		addr += vga.svga.bank_write_full;
520 		addr = CHECKED(addr);
521 		MEM_CHANGED( addr );
522 		hostWrite<Bit8u>( &vga.mem.linear[addr], val );
523 	}
writew(PhysPt addr,Bitu val)524 	void writew(PhysPt addr,Bitu val) {
525 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
526 		addr += vga.svga.bank_write_full;
527 		addr = CHECKED(addr);
528 		MEM_CHANGED( addr );
529 		hostWrite<Bit16u>( &vga.mem.linear[addr], val );
530 	}
writed(PhysPt addr,Bitu val)531 	void writed(PhysPt addr,Bitu val) {
532 		addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
533 		addr += vga.svga.bank_write_full;
534 		addr = CHECKED(addr);
535 		MEM_CHANGED( addr );
536 		hostWrite<Bit32u>( &vga.mem.linear[addr], val );
537 	}
538 };
539 
540 class VGA_LIN4_Handler : public VGA_UnchainedEGA_Handler {
541 public:
VGA_LIN4_Handler()542 	VGA_LIN4_Handler() {
543 		flags=PFLAG_NOCODE;
544 	}
writeb(PhysPt addr,Bitu val)545 	void writeb(PhysPt addr,Bitu val) {
546 		addr = vga.svga.bank_write_full + (PAGING_GetPhysicalAddress(addr) & 0xffff);
547 		addr = CHECKED4(addr);
548 		MEM_CHANGED( addr << 3 );
549 		writeHandler<false>(addr+0,(Bit8u)(val >> 0));
550 	}
writew(PhysPt addr,Bitu val)551 	void writew(PhysPt addr,Bitu val) {
552 		addr = vga.svga.bank_write_full + (PAGING_GetPhysicalAddress(addr) & 0xffff);
553 		addr = CHECKED4(addr);
554 		MEM_CHANGED( addr << 3 );
555 		writeHandler<false>(addr+0,(Bit8u)(val >> 0));
556 		writeHandler<false>(addr+1,(Bit8u)(val >> 8));
557 	}
writed(PhysPt addr,Bitu val)558 	void writed(PhysPt addr,Bitu val) {
559 		addr = vga.svga.bank_write_full + (PAGING_GetPhysicalAddress(addr) & 0xffff);
560 		addr = CHECKED4(addr);
561 		MEM_CHANGED( addr << 3 );
562 		writeHandler<false>(addr+0,(Bit8u)(val >> 0));
563 		writeHandler<false>(addr+1,(Bit8u)(val >> 8));
564 		writeHandler<false>(addr+2,(Bit8u)(val >> 16));
565 		writeHandler<false>(addr+3,(Bit8u)(val >> 24));
566 	}
readb(PhysPt addr)567 	Bitu readb(PhysPt addr) {
568 		addr = vga.svga.bank_read_full + (PAGING_GetPhysicalAddress(addr) & 0xffff);
569 		addr = CHECKED4(addr);
570 		return readHandler(addr);
571 	}
readw(PhysPt addr)572 	Bitu readw(PhysPt addr) {
573 		addr = vga.svga.bank_read_full + (PAGING_GetPhysicalAddress(addr) & 0xffff);
574 		addr = CHECKED4(addr);
575 		Bitu ret = (readHandler(addr+0) << 0);
576 		ret     |= (readHandler(addr+1) << 8);
577 		return ret;
578 	}
readd(PhysPt addr)579 	Bitu readd(PhysPt addr) {
580 		addr = vga.svga.bank_read_full + (PAGING_GetPhysicalAddress(addr) & 0xffff);
581 		addr = CHECKED4(addr);
582 		Bitu ret = (readHandler(addr+0) << 0);
583 		ret     |= (readHandler(addr+1) << 8);
584 		ret     |= (readHandler(addr+2) << 16);
585 		ret     |= (readHandler(addr+3) << 24);
586 		return ret;
587 	}
588 };
589 
590 
591 class VGA_LFBChanges_Handler : public PageHandler {
592 public:
VGA_LFBChanges_Handler()593 	VGA_LFBChanges_Handler() {
594 		flags=PFLAG_NOCODE;
595 	}
readb(PhysPt addr)596 	Bitu readb(PhysPt addr) {
597 		addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr;
598 		addr = CHECKED(addr);
599 		return hostRead<Bit8u>( &vga.mem.linear[addr] );
600 	}
readw(PhysPt addr)601 	Bitu readw(PhysPt addr) {
602 		addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr;
603 		addr = CHECKED(addr);
604 		return hostRead<Bit16u>( &vga.mem.linear[addr] );
605 	}
readd(PhysPt addr)606 	Bitu readd(PhysPt addr) {
607 		addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr;
608 		addr = CHECKED(addr);
609 		return hostRead<Bit32u>( &vga.mem.linear[addr] );
610 	}
writeb(PhysPt addr,Bitu val)611 	void writeb(PhysPt addr,Bitu val) {
612 		addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr;
613 		addr = CHECKED(addr);
614 		hostWrite<Bit8u>( &vga.mem.linear[addr], val );
615 		MEM_CHANGED( addr );
616 	}
writew(PhysPt addr,Bitu val)617 	void writew(PhysPt addr,Bitu val) {
618 		addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr;
619 		addr = CHECKED(addr);
620 		hostWrite<Bit16u>( &vga.mem.linear[addr], val );
621 		MEM_CHANGED( addr );
622 	}
writed(PhysPt addr,Bitu val)623 	void writed(PhysPt addr,Bitu val) {
624 		addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr;
625 		addr = CHECKED(addr);
626 		hostWrite<Bit32u>( &vga.mem.linear[addr], val );
627 		MEM_CHANGED( addr );
628 	}
629 };
630 
631 class VGA_LFB_Handler : public PageHandler {
632 public:
VGA_LFB_Handler()633 	VGA_LFB_Handler() {
634 		flags=PFLAG_READABLE|PFLAG_WRITEABLE|PFLAG_NOCODE;
635 	}
GetHostReadPt(Bitu phys_page)636 	HostPt GetHostReadPt( Bitu phys_page ) {
637 		phys_page -= vga.lfb.page;
638 		return &vga.mem.linear[CHECKED3(phys_page * 4096)];
639 	}
GetHostWritePt(Bitu phys_page)640 	HostPt GetHostWritePt( Bitu phys_page ) {
641 		return GetHostReadPt( phys_page );
642 	}
643 };
644 
645 extern void XGA_Write(Bitu port, Bitu val, Bitu len);
646 extern Bitu XGA_Read(Bitu port, Bitu len);
647 
648 class VGA_MMIO_Handler : public PageHandler {
649 public:
VGA_MMIO_Handler()650 	VGA_MMIO_Handler() {
651 		flags=PFLAG_NOCODE;
652 	}
writeb(PhysPt addr,Bitu val)653 	void writeb(PhysPt addr,Bitu val) {
654 		Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff;
655 		XGA_Write(port, val, 1);
656 	}
writew(PhysPt addr,Bitu val)657 	void writew(PhysPt addr,Bitu val) {
658 		Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff;
659 		XGA_Write(port, val, 2);
660 	}
writed(PhysPt addr,Bitu val)661 	void writed(PhysPt addr,Bitu val) {
662 		Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff;
663 		XGA_Write(port, val, 4);
664 	}
665 
readb(PhysPt addr)666 	Bitu readb(PhysPt addr) {
667 		Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff;
668 		return XGA_Read(port, 1);
669 	}
readw(PhysPt addr)670 	Bitu readw(PhysPt addr) {
671 		Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff;
672 		return XGA_Read(port, 2);
673 	}
readd(PhysPt addr)674 	Bitu readd(PhysPt addr) {
675 		Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff;
676 		return XGA_Read(port, 4);
677 	}
678 };
679 
680 class VGA_TANDY_PageHandler : public PageHandler {
681 public:
VGA_TANDY_PageHandler()682 	VGA_TANDY_PageHandler() {
683 		flags=PFLAG_READABLE|PFLAG_WRITEABLE;
684 //			|PFLAG_NOCODE;
685 	}
GetHostReadPt(Bitu phys_page)686 	HostPt GetHostReadPt(Bitu phys_page) {
687 		if (vga.tandy.mem_bank & 1)
688 			phys_page&=0x03;
689 		else
690 			phys_page&=0x07;
691 		return vga.tandy.mem_base + (phys_page * 4096);
692 	}
GetHostWritePt(Bitu phys_page)693 	HostPt GetHostWritePt(Bitu phys_page) {
694 		return GetHostReadPt( phys_page );
695 	}
696 };
697 
698 
699 class VGA_PCJR_Handler : public PageHandler {
700 public:
VGA_PCJR_Handler()701 	VGA_PCJR_Handler() {
702 		flags=PFLAG_READABLE|PFLAG_WRITEABLE;
703 	}
GetHostReadPt(Bitu phys_page)704 	HostPt GetHostReadPt(Bitu phys_page) {
705 		phys_page-=0xb8;
706 		//test for a unaliged bank, then replicate 2x16kb
707 		if (vga.tandy.mem_bank & 1)
708 			phys_page&=0x03;
709 		return vga.tandy.mem_base + (phys_page * 4096);
710 	}
GetHostWritePt(Bitu phys_page)711 	HostPt GetHostWritePt(Bitu phys_page) {
712 		return GetHostReadPt( phys_page );
713 	}
714 };
715 
716 class VGA_Empty_Handler : public PageHandler {
717 public:
VGA_Empty_Handler()718 	VGA_Empty_Handler() {
719 		flags=PFLAG_NOCODE;
720 	}
readb(PhysPt)721 	Bitu readb(PhysPt /*addr*/) {
722 //		LOG(LOG_VGA, LOG_NORMAL ) ( "Read from empty memory space at %x", addr );
723 		return 0xff;
724 	}
writeb(PhysPt,Bitu)725 	void writeb(PhysPt /*addr*/,Bitu /*val*/) {
726 //		LOG(LOG_VGA, LOG_NORMAL ) ( "Write %x to empty memory space at %x", val, addr );
727 	}
728 };
729 
730 static struct vg {
731 	VGA_Map_Handler				map;
732 	VGA_Changes_Handler			changes;
733 	VGA_TEXT_PageHandler		text;
734 	VGA_TANDY_PageHandler		tandy;
735 	VGA_ChainedEGA_Handler		cega;
736 	VGA_ChainedVGA_Handler		cvga;
737 	VGA_UnchainedEGA_Handler	uega;
738 	VGA_UnchainedVGA_Handler	uvga;
739 	VGA_PCJR_Handler			pcjr;
740 	VGA_LIN4_Handler			lin4;
741 	VGA_LFB_Handler				lfb;
742 	VGA_LFBChanges_Handler		lfbchanges;
743 	VGA_MMIO_Handler			mmio;
744 	VGA_Empty_Handler			empty;
745 } vgaph;
746 
VGA_ChangedBank(void)747 void VGA_ChangedBank(void) {
748 #ifndef VGA_LFB_MAPPED
749 	//If the mode is accurate than the correct mapper must have been installed already
750 	if ( vga.mode >= M_LIN4 && vga.mode <= M_LIN32 ) {
751 		return;
752 	}
753 #endif
754 	VGA_SetupHandlers();
755 }
756 
VGA_SetupHandlers(void)757 void VGA_SetupHandlers(void) {
758 	vga.svga.bank_read_full = vga.svga.bank_read*vga.svga.bank_size;
759 	vga.svga.bank_write_full = vga.svga.bank_write*vga.svga.bank_size;
760 
761 	PageHandler *newHandler;
762 	switch (machine) {
763 	case MCH_CGA:
764 	case MCH_PCJR:
765 		MEM_SetPageHandler( VGA_PAGE_B8, 8, &vgaph.pcjr );
766 		goto range_done;
767 	case MCH_HERC:
768 		vgapages.base=VGA_PAGE_B0;
769 		if (vga.herc.enable_bits & 0x2) {
770 			vgapages.mask=0xffff;
771 			MEM_SetPageHandler(VGA_PAGE_B0,16,&vgaph.map);
772 		} else {
773 			vgapages.mask=0x7fff;
774 			/* With hercules in 32kb mode it leaves a memory hole on 0xb800 */
775 			MEM_SetPageHandler(VGA_PAGE_B0,8,&vgaph.map);
776 			MEM_SetPageHandler(VGA_PAGE_B8,8,&vgaph.empty);
777 		}
778 		goto range_done;
779 	case MCH_TANDY:
780 		/* Always map 0xa000 - 0xbfff, might overwrite 0xb800 */
781 		vgapages.base=VGA_PAGE_A0;
782 		vgapages.mask=0x1ffff;
783 		MEM_SetPageHandler(VGA_PAGE_A0, 32, &vgaph.map );
784 		if ( vga.tandy.extended_ram & 1 ) {
785 			//You seem to be able to also map different 64kb banks, but have to figure that out
786 			//This seems to work so far though
787 			vga.tandy.draw_base = vga.mem.linear;
788 			vga.tandy.mem_base = vga.mem.linear;
789 		} else {
790 			vga.tandy.draw_base = TANDY_VIDBASE( vga.tandy.draw_bank * 16 * 1024);
791 			vga.tandy.mem_base = TANDY_VIDBASE( vga.tandy.mem_bank * 16 * 1024);
792 			MEM_SetPageHandler( 0xb8, 8, &vgaph.tandy );
793 		}
794 		goto range_done;
795 //		MEM_SetPageHandler(vga.tandy.mem_bank<<2,vga.tandy.is_32k_mode ? 0x08 : 0x04,range_handler);
796 	case EGAVGA_ARCH_CASE:
797 		break;
798 	default:
799 		LOG_MSG("Illegal machine type %d", machine );
800 		return;
801 	}
802 
803 	/* This should be vga only */
804 	switch (vga.mode) {
805 	case M_ERROR:
806 	default:
807 		return;
808 	case M_LIN4:
809 		newHandler = &vgaph.lin4;
810 		break;
811 	case M_LIN15:
812 	case M_LIN16:
813 	case M_LIN32:
814 #ifdef VGA_LFB_MAPPED
815 		newHandler = &vgaph.map;
816 #else
817 		newHandler = &vgaph.changes;
818 #endif
819 		break;
820 	case M_LIN8:
821 	case M_VGA:
822 		if (vga.config.chained) {
823 			if(vga.config.compatible_chain4)
824 				newHandler = &vgaph.cvga;
825 			else
826 #ifdef VGA_LFB_MAPPED
827 				newHandler = &vgaph.map;
828 #else
829 				newHandler = &vgaph.changes;
830 #endif
831 		} else {
832 			newHandler = &vgaph.uvga;
833 		}
834 		break;
835 	case M_EGA:
836 		if (vga.config.chained)
837 			newHandler = &vgaph.cega;
838 		else
839 			newHandler = &vgaph.uega;
840 		break;
841 	case M_TEXT:
842 		/* Check if we're not in odd/even mode */
843 		if (vga.gfx.miscellaneous & 0x2) newHandler = &vgaph.map;
844 		else newHandler = &vgaph.text;
845 		break;
846 	case M_CGA4:
847 	case M_CGA2:
848 		newHandler = &vgaph.map;
849 		break;
850 	}
851 	switch ((vga.gfx.miscellaneous >> 2) & 3) {
852 	case 0:
853 		vgapages.base = VGA_PAGE_A0;
854 		switch (svgaCard) {
855 		case SVGA_TsengET3K:
856 		case SVGA_TsengET4K:
857 			vgapages.mask = 0xffff;
858 			break;
859 		case SVGA_S3Trio:
860 		default:
861 			vgapages.mask = 0x1ffff;
862 			break;
863 		}
864 		MEM_SetPageHandler(VGA_PAGE_A0, 32, newHandler );
865 		break;
866 	case 1:
867 		vgapages.base = VGA_PAGE_A0;
868 		vgapages.mask = 0xffff;
869 		MEM_SetPageHandler( VGA_PAGE_A0, 16, newHandler );
870 		MEM_ResetPageHandler( VGA_PAGE_B0, 16);
871 		break;
872 	case 2:
873 		vgapages.base = VGA_PAGE_B0;
874 		vgapages.mask = 0x7fff;
875 		MEM_SetPageHandler( VGA_PAGE_B0, 8, newHandler );
876 		MEM_ResetPageHandler( VGA_PAGE_A0, 16 );
877 		MEM_ResetPageHandler( VGA_PAGE_B8, 8 );
878 		break;
879 	case 3:
880 		vgapages.base = VGA_PAGE_B8;
881 		vgapages.mask = 0x7fff;
882 		MEM_SetPageHandler( VGA_PAGE_B8, 8, newHandler );
883 		MEM_ResetPageHandler( VGA_PAGE_A0, 16 );
884 		MEM_ResetPageHandler( VGA_PAGE_B0, 8 );
885 		break;
886 	}
887 	if(svgaCard == SVGA_S3Trio && (vga.s3.ext_mem_ctrl & 0x10))
888 		MEM_SetPageHandler(VGA_PAGE_A0, 16, &vgaph.mmio);
889 range_done:
890 	PAGING_ClearTLB();
891 }
892 
VGA_StartUpdateLFB(void)893 void VGA_StartUpdateLFB(void) {
894 	vga.lfb.page = vga.s3.la_window << 4;
895 	vga.lfb.addr = vga.s3.la_window << 16;
896 #ifdef VGA_LFB_MAPPED
897 	vga.lfb.handler = &vgaph.lfb;
898 #else
899 	vga.lfb.handler = &vgaph.lfbchanges;
900 #endif
901 	MEM_SetLFB(vga.s3.la_window << 4 ,vga.vmemsize/4096, vga.lfb.handler, &vgaph.mmio);
902 }
903 
VGA_Memory_ShutDown(Section *)904 static void VGA_Memory_ShutDown(Section * /*sec*/) {
905 	delete[] vga.mem.linear_orgptr;
906 	delete[] vga.fastmem_orgptr;
907 #ifdef VGA_KEEP_CHANGES
908 	delete[] vga.changes.map;
909 #endif
910 }
911 
VGA_SetupMemory(Section * sec)912 void VGA_SetupMemory(Section* sec) {
913 	vga.svga.bank_read = vga.svga.bank_write = 0;
914 	vga.svga.bank_read_full = vga.svga.bank_write_full = 0;
915 
916 	Bit32u vga_allocsize=vga.vmemsize;
917 	// Keep lower limit at 512k
918 	if (vga_allocsize<512*1024) vga_allocsize=512*1024;
919 	// We reserve extra 2K for one scan line
920 	vga_allocsize+=2048;
921 	vga.mem.linear_orgptr = new Bit8u[vga_allocsize+16];
922 	vga.mem.linear=(Bit8u*)(((Bitu)vga.mem.linear_orgptr + 16-1) & ~(16-1));
923 	memset(vga.mem.linear,0,vga_allocsize);
924 
925 	vga.fastmem_orgptr = new Bit8u[(vga.vmemsize<<1)+4096+16];
926 	vga.fastmem=(Bit8u*)(((Bitu)vga.fastmem_orgptr + 16-1) & ~(16-1));
927 
928 	// In most cases these values stay the same. Assumptions: vmemwrap is power of 2,
929 	// vmemwrap <= vmemsize, fastmem implicitly has mem wrap twice as big
930 	vga.vmemwrap = vga.vmemsize;
931 
932 #ifdef VGA_KEEP_CHANGES
933 	memset( &vga.changes, 0, sizeof( vga.changes ));
934 	int changesMapSize = (vga.vmemsize >> VGA_CHANGE_SHIFT) + 32;
935 	vga.changes.map = new Bit8u[changesMapSize];
936 	memset(vga.changes.map, 0, changesMapSize);
937 #endif
938 	vga.svga.bank_read = vga.svga.bank_write = 0;
939 	vga.svga.bank_read_full = vga.svga.bank_write_full = 0;
940 	vga.svga.bank_size = 0x10000; /* most common bank size is 64K */
941 
942 	sec->AddDestroyFunction(&VGA_Memory_ShutDown);
943 
944 	if (machine==MCH_PCJR) {
945 		/* PCJr does not have dedicated graphics memory but uses
946 		   conventional memory below 128k */
947 		//TODO map?
948 	}
949 }
950