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_xga.cpp,v 1.17 2009-05-27 09:15:41 qbix79 Exp $ */
20 
21 #include <string.h>
22 #include "dosbox.h"
23 #include "inout.h"
24 #include "vga.h"
25 #include <math.h>
26 #include <stdio.h>
27 #include "callback.h"
28 #include "cpu.h"		// for 0x3da delay
29 
30 #define XGA_SCREEN_WIDTH	vga.s3.xga_screen_width
31 #define XGA_COLOR_MODE		vga.s3.xga_color_mode
32 
33 #define XGA_SHOW_COMMAND_TRACE 0
34 
35 struct XGAStatus {
36 	struct scissorreg {
37 		Bit16u x1, y1, x2, y2;
38 	} scissors;
39 
40 	Bit32u readmask;
41 	Bit32u writemask;
42 
43 	Bit32u forecolor;
44 	Bit32u backcolor;
45 
46 	Bitu curcommand;
47 
48 	Bit16u foremix;
49 	Bit16u backmix;
50 
51 	Bit16u curx, cury;
52 	Bit16u destx, desty;
53 
54 	Bit16u ErrTerm;
55 	Bit16u MIPcount;
56 	Bit16u MAPcount;
57 
58 	Bit16u pix_cntl;
59 	Bit16u control1;
60 	Bit16u control2;
61 	Bit16u read_sel;
62 
63 	struct XGA_WaitCmd {
64 		bool newline;
65 		bool wait;
66 		Bit16u cmd;
67 		Bit16u curx, cury;
68 		Bit16u x1, y1, x2, y2, sizex, sizey;
69 		Bit32u data; /* transient data passed by multiple calls */
70 		Bitu datasize;
71 		Bitu buswidth;
72 	} waitcmd;
73 
74 } xga;
75 
XGA_Write_Multifunc(Bitu val,Bitu len)76 void XGA_Write_Multifunc(Bitu val, Bitu len) {
77 	Bitu regselect = val >> 12;
78 	Bitu dataval = val & 0xfff;
79 	switch(regselect) {
80 		case 0: // minor axis pixel count
81 			xga.MIPcount = dataval;
82 			break;
83 		case 1: // top scissors
84 			xga.scissors.y1 = dataval;
85 			break;
86 		case 2: // left
87 			xga.scissors.x1 = dataval;
88 			break;
89 		case 3: // bottom
90 			xga.scissors.y2 = dataval;
91 			break;
92 		case 4: // right
93 			xga.scissors.x2 = dataval;
94 			break;
95 		case 0xa: // data manip control
96 			xga.pix_cntl = dataval;
97 			break;
98 		case 0xd: // misc 2
99 			xga.control2 = dataval;
100 			break;
101 		case 0xe:
102 			xga.control1 = dataval;
103 			break;
104 		case 0xf:
105 			xga.read_sel = dataval;
106 			break;
107 		default:
108 			LOG_MSG("XGA: Unhandled multifunction command %x", regselect);
109 			break;
110 	}
111 }
112 
XGA_Read_Multifunc()113 Bitu XGA_Read_Multifunc() {
114 	switch(xga.read_sel++) {
115 		case 0: return xga.MIPcount;
116 		case 1: return xga.scissors.y1;
117 		case 2: return xga.scissors.x1;
118 		case 3: return xga.scissors.y2;
119 		case 4: return xga.scissors.x2;
120 		case 5: return xga.pix_cntl;
121 		case 6: return xga.control1;
122 		case 7: return 0; // TODO
123 		case 8: return 0; // TODO
124 		case 9: return 0; // TODO
125 		case 10: return xga.control2;
126 		default: return 0;
127 	}
128 }
129 
130 
XGA_DrawPoint(Bitu x,Bitu y,Bitu c)131 void XGA_DrawPoint(Bitu x, Bitu y, Bitu c) {
132 	if(!(xga.curcommand & 0x1)) return;
133 	if(!(xga.curcommand & 0x10)) return;
134 
135 	if(x < xga.scissors.x1) return;
136 	if(x > xga.scissors.x2) return;
137 	if(y < xga.scissors.y1) return;
138 	if(y > xga.scissors.y2) return;
139 
140 	Bit32u memaddr = (y * XGA_SCREEN_WIDTH) + x;
141 	/* Need to zero out all unused bits in modes that have any (15-bit or "32"-bit -- the last
142 	   one is actually 24-bit. Without this step there may be some graphics corruption (mainly,
143 	   during windows dragging. */
144 	switch(XGA_COLOR_MODE) {
145 		case M_LIN8:
146 			if (GCC_UNLIKELY(memaddr >= vga.vmemsize)) break;
147 			vga.mem.linear[memaddr] = c;
148 			break;
149 		case M_LIN15:
150 			if (GCC_UNLIKELY(memaddr*2 >= vga.vmemsize)) break;
151 			((Bit16u*)(vga.mem.linear))[memaddr] = (Bit16u)(c&0x7fff);
152 			break;
153 		case M_LIN16:
154 			if (GCC_UNLIKELY(memaddr*2 >= vga.vmemsize)) break;
155 			((Bit16u*)(vga.mem.linear))[memaddr] = (Bit16u)(c&0xffff);
156 			break;
157 		case M_LIN32:
158 			if (GCC_UNLIKELY(memaddr*4 >= vga.vmemsize)) break;
159 			((Bit32u*)(vga.mem.linear))[memaddr] = c;
160 			break;
161 		default:
162 			break;
163 	}
164 
165 }
166 
XGA_GetPoint(Bitu x,Bitu y)167 Bitu XGA_GetPoint(Bitu x, Bitu y) {
168 	Bit32u memaddr = (y * XGA_SCREEN_WIDTH) + x;
169 
170 	switch(XGA_COLOR_MODE) {
171 	case M_LIN8:
172 		if (GCC_UNLIKELY(memaddr >= vga.vmemsize)) break;
173 		return vga.mem.linear[memaddr];
174 	case M_LIN15:
175 	case M_LIN16:
176 		if (GCC_UNLIKELY(memaddr*2 >= vga.vmemsize)) break;
177 		return ((Bit16u*)(vga.mem.linear))[memaddr];
178 	case M_LIN32:
179 		if (GCC_UNLIKELY(memaddr*4 >= vga.vmemsize)) break;
180 		return ((Bit32u*)(vga.mem.linear))[memaddr];
181 	default:
182 		break;
183 	}
184 	return 0;
185 }
186 
187 
XGA_GetMixResult(Bitu mixmode,Bitu srcval,Bitu dstdata)188 Bitu XGA_GetMixResult(Bitu mixmode, Bitu srcval, Bitu dstdata) {
189 	Bitu destval = 0;
190 	switch(mixmode &  0xf) {
191 		case 0x00: /* not DST */
192 			destval = ~dstdata;
193 			break;
194 		case 0x01: /* 0 (false) */
195 			destval = 0;
196 			break;
197 		case 0x02: /* 1 (true) */
198 			destval = 0xffffffff;
199 			break;
200 		case 0x03: /* 2 DST */
201 			destval = dstdata;
202 			break;
203 		case 0x04: /* not SRC */
204 			destval = ~srcval;
205 			break;
206 		case 0x05: /* SRC xor DST */
207 			destval = srcval ^ dstdata;
208 			break;
209 		case 0x06: /* not (SRC xor DST) */
210 			destval = ~(srcval ^ dstdata);
211 			break;
212 		case 0x07: /* SRC */
213 			destval = srcval;
214 			break;
215 		case 0x08: /* not (SRC and DST) */
216 			destval = ~(srcval & dstdata);
217 			break;
218 		case 0x09: /* (not SRC) or DST */
219 			destval = (~srcval) | dstdata;
220 			break;
221 		case 0x0a: /* SRC or (not DST) */
222 			destval = srcval | (~dstdata);
223 			break;
224 		case 0x0b: /* SRC or DST */
225 			destval = srcval | dstdata;
226 			break;
227 		case 0x0c: /* SRC and DST */
228 			destval = srcval & dstdata;
229 			break;
230 		case 0x0d: /* SRC and (not DST) */
231 			destval = srcval & (~dstdata);
232 			break;
233 		case 0x0e: /* (not SRC) and DST */
234 			destval = (~srcval) & dstdata;
235 			break;
236 		case 0x0f: /* not (SRC or DST) */
237 			destval = ~(srcval | dstdata);
238 			break;
239 		default:
240 			LOG_MSG("XGA: GetMixResult: Unknown mix.  Shouldn't be able to get here!");
241 			break;
242 	}
243 	return destval;
244 }
245 
XGA_DrawLineVector(Bitu val)246 void XGA_DrawLineVector(Bitu val) {
247 	Bits xat, yat;
248 	Bitu srcval;
249 	Bitu destval;
250 	Bitu dstdata;
251 	Bits i;
252 
253 	Bits dx, sx, sy;
254 
255 	dx = xga.MAPcount;
256 	xat = xga.curx;
257 	yat = xga.cury;
258 
259 	switch((val >> 5) & 0x7) {
260 		case 0x00: /* 0 degrees */
261 			sx = 1;
262 			sy = 0;
263 			break;
264 		case 0x01: /* 45 degrees */
265 			sx = 1;
266 			sy = -1;
267 			break;
268 		case 0x02: /* 90 degrees */
269 			sx = 0;
270 			sy = -1;
271 			break;
272 		case 0x03: /* 135 degrees */
273 			sx = -1;
274 			sy = -1;
275 			break;
276 		case 0x04: /* 180 degrees */
277 			sx = -1;
278 			sy = 0;
279 			break;
280 		case 0x05: /* 225 degrees */
281 			sx = -1;
282 			sy = 1;
283 			break;
284 		case 0x06: /* 270 degrees */
285 			sx = 0;
286 			sy = 1;
287 			break;
288 		case 0x07: /* 315 degrees */
289 			sx = 1;
290 			sy = 1;
291 			break;
292 		default:  // Should never get here
293 			sx = 0;
294 			sy = 0;
295 			break;
296 	}
297 
298 	for (i=0;i<=dx;i++) {
299 		Bitu mixmode = (xga.pix_cntl >> 6) & 0x3;
300 		switch (mixmode) {
301 			case 0x00: /* FOREMIX always used */
302 				mixmode = xga.foremix;
303 				switch((mixmode >> 5) & 0x03) {
304 					case 0x00: /* Src is background color */
305 						srcval = xga.backcolor;
306 						break;
307 					case 0x01: /* Src is foreground color */
308 						srcval = xga.forecolor;
309 						break;
310 					case 0x02: /* Src is pixel data from PIX_TRANS register */
311 						//srcval = tmpval;
312 						//LOG_MSG("XGA: DrawRect: Wants data from PIX_TRANS register");
313 						break;
314 					case 0x03: /* Src is bitmap data */
315 						LOG_MSG("XGA: DrawRect: Wants data from srcdata");
316 						//srcval = srcdata;
317 						break;
318 					default:
319 						LOG_MSG("XGA: DrawRect: Shouldn't be able to get here!");
320 						break;
321 				}
322 				dstdata = XGA_GetPoint(xat,yat);
323 
324 				destval = XGA_GetMixResult(mixmode, srcval, dstdata);
325 
326                 XGA_DrawPoint(xat,yat, destval);
327 				break;
328 			default:
329 				LOG_MSG("XGA: DrawLine: Needs mixmode %x", mixmode);
330 				break;
331 		}
332 		xat += sx;
333 		yat += sy;
334 	}
335 
336 	xga.curx = xat-1;
337 	xga.cury = yat;
338 }
339 
XGA_DrawLineBresenham(Bitu val)340 void XGA_DrawLineBresenham(Bitu val) {
341 	Bits xat, yat;
342 	Bitu srcval;
343 	Bitu destval;
344 	Bitu dstdata;
345 	Bits i;
346 	Bits tmpswap;
347 	bool steep;
348 
349 #define SWAP(a,b) tmpswap = a; a = b; b = tmpswap;
350 
351 	Bits dx, sx, dy, sy, e, dmajor, dminor,destxtmp;
352 
353 	// Probably a lot easier way to do this, but this works.
354 
355 	dminor = (Bits)((Bit16s)xga.desty);
356 	if(xga.desty&0x2000) dminor |= ~0x1fff;
357 	dminor >>= 1;
358 
359 	destxtmp=(Bits)((Bit16s)xga.destx);
360 	if(xga.destx&0x2000) destxtmp |= ~0x1fff;
361 
362 
363 	dmajor = -(destxtmp - (dminor << 1)) >> 1;
364 
365 	dx = dmajor;
366 	if((val >> 5) & 0x1) {
367         sx = 1;
368 	} else {
369 		sx = -1;
370 	}
371 	dy = dminor;
372 	if((val >> 7) & 0x1) {
373         sy = 1;
374 	} else {
375 		sy = -1;
376 	}
377 	e = (Bits)((Bit16s)xga.ErrTerm);
378 	if(xga.ErrTerm&0x2000) e |= ~0x1fff;
379 	xat = xga.curx;
380 	yat = xga.cury;
381 
382 	if((val >> 6) & 0x1) {
383 		steep = false;
384 		SWAP(xat, yat);
385 		SWAP(sx, sy);
386 	} else {
387 		steep = true;
388 	}
389 
390 	//LOG_MSG("XGA: Bresenham: ASC %d, LPDSC %d, sx %d, sy %d, err %d, steep %d, length %d, dmajor %d, dminor %d, xstart %d, ystart %d", dx, dy, sx, sy, e, steep, xga.MAPcount, dmajor, dminor,xat,yat);
391 
392 	for (i=0;i<=xga.MAPcount;i++) {
393 			Bitu mixmode = (xga.pix_cntl >> 6) & 0x3;
394 			switch (mixmode) {
395 				case 0x00: /* FOREMIX always used */
396 					mixmode = xga.foremix;
397 					switch((mixmode >> 5) & 0x03) {
398 						case 0x00: /* Src is background color */
399 							srcval = xga.backcolor;
400 							break;
401 						case 0x01: /* Src is foreground color */
402 							srcval = xga.forecolor;
403 							break;
404 						case 0x02: /* Src is pixel data from PIX_TRANS register */
405 							//srcval = tmpval;
406 							LOG_MSG("XGA: DrawRect: Wants data from PIX_TRANS register");
407 							break;
408 						case 0x03: /* Src is bitmap data */
409 							LOG_MSG("XGA: DrawRect: Wants data from srcdata");
410 							//srcval = srcdata;
411 							break;
412 						default:
413 							LOG_MSG("XGA: DrawRect: Shouldn't be able to get here!");
414 							break;
415 					}
416 
417 					if(steep) {
418 						dstdata = XGA_GetPoint(xat,yat);
419 					} else {
420 						dstdata = XGA_GetPoint(yat,xat);
421 					}
422 
423 					destval = XGA_GetMixResult(mixmode, srcval, dstdata);
424 
425 					if(steep) {
426 						XGA_DrawPoint(xat,yat, destval);
427 					} else {
428 						XGA_DrawPoint(yat,xat, destval);
429 					}
430 
431 					break;
432 				default:
433 					LOG_MSG("XGA: DrawLine: Needs mixmode %x", mixmode);
434 					break;
435 			}
436 			while (e > 0) {
437 				yat += sy;
438 				e -= (dx << 1);
439 			}
440 			xat += sx;
441 			e += (dy << 1);
442 	}
443 
444 	if(steep) {
445 		xga.curx = xat;
446 		xga.cury = yat;
447 	} else {
448 		xga.curx = yat;
449 		xga.cury = xat;
450 	}
451 	//	}
452 	//}
453 
454 }
455 
XGA_DrawRectangle(Bitu val)456 void XGA_DrawRectangle(Bitu val) {
457 	Bit32u xat, yat;
458 	Bitu srcval;
459 	Bitu destval;
460 	Bitu dstdata;
461 
462 	Bits srcx, srcy, dx, dy;
463 
464 	dx = -1;
465 	dy = -1;
466 
467 	if(((val >> 5) & 0x01) != 0) dx = 1;
468 	if(((val >> 7) & 0x01) != 0) dy = 1;
469 
470 	srcy = xga.cury;
471 
472 	for(yat=0;yat<=xga.MIPcount;yat++) {
473 		srcx = xga.curx;
474 		for(xat=0;xat<=xga.MAPcount;xat++) {
475 			Bitu mixmode = (xga.pix_cntl >> 6) & 0x3;
476 			switch (mixmode) {
477 				case 0x00: /* FOREMIX always used */
478 					mixmode = xga.foremix;
479 					switch((mixmode >> 5) & 0x03) {
480 						case 0x00: /* Src is background color */
481 							srcval = xga.backcolor;
482 							break;
483 						case 0x01: /* Src is foreground color */
484 							srcval = xga.forecolor;
485 							break;
486 						case 0x02: /* Src is pixel data from PIX_TRANS register */
487 							//srcval = tmpval;
488 							LOG_MSG("XGA: DrawRect: Wants data from PIX_TRANS register");
489 							break;
490 						case 0x03: /* Src is bitmap data */
491 							LOG_MSG("XGA: DrawRect: Wants data from srcdata");
492 							//srcval = srcdata;
493 							break;
494 						default:
495 							LOG_MSG("XGA: DrawRect: Shouldn't be able to get here!");
496 							break;
497 					}
498 					dstdata = XGA_GetPoint(srcx,srcy);
499 
500 					destval = XGA_GetMixResult(mixmode, srcval, dstdata);
501 
502                     XGA_DrawPoint(srcx,srcy, destval);
503 					break;
504 				default:
505 					LOG_MSG("XGA: DrawRect: Needs mixmode %x", mixmode);
506 					break;
507 			}
508 			srcx += dx;
509 		}
510 		srcy += dy;
511 	}
512 	xga.curx = srcx;
513 	xga.cury = srcy;
514 
515 	//LOG_MSG("XGA: Draw rect (%d, %d)-(%d, %d), %d", x1, y1, x2, y2, xga.forecolor);
516 }
517 
XGA_CheckX(void)518 bool XGA_CheckX(void) {
519 	bool newline = false;
520 	if(!xga.waitcmd.newline) {
521 
522 	if((xga.waitcmd.curx<2048) && xga.waitcmd.curx > (xga.waitcmd.x2)) {
523 		xga.waitcmd.curx = xga.waitcmd.x1;
524 		xga.waitcmd.cury++;
525 		xga.waitcmd.cury&=0x0fff;
526 		newline = true;
527 		xga.waitcmd.newline = true;
528 		if((xga.waitcmd.cury<2048)&&(xga.waitcmd.cury > xga.waitcmd.y2))
529 			xga.waitcmd.wait = false;
530 	} else if(xga.waitcmd.curx>=2048) {
531 		Bit16u realx = 4096-xga.waitcmd.curx;
532 		if(xga.waitcmd.x2>2047) { // x end is negative too
533 			Bit16u realxend=4096-xga.waitcmd.x2;
534 			if(realx==realxend) {
535 				xga.waitcmd.curx = xga.waitcmd.x1;
536 				xga.waitcmd.cury++;
537 				xga.waitcmd.cury&=0x0fff;
538 				newline = true;
539 				xga.waitcmd.newline = true;
540 				if((xga.waitcmd.cury<2048)&&(xga.waitcmd.cury > xga.waitcmd.y2))
541 					xga.waitcmd.wait = false;
542 			}
543 		} else { // else overlapping
544 			if(realx==xga.waitcmd.x2) {
545 				xga.waitcmd.curx = xga.waitcmd.x1;
546 				xga.waitcmd.cury++;
547 				xga.waitcmd.cury&=0x0fff;
548 				newline = true;
549 				xga.waitcmd.newline = true;
550 				if((xga.waitcmd.cury<2048)&&(xga.waitcmd.cury > xga.waitcmd.y2))
551 					xga.waitcmd.wait = false;
552 				}
553 			}
554 		}
555 	} else {
556         xga.waitcmd.newline = false;
557 	}
558 	return newline;
559 }
560 
XGA_DrawWaitSub(Bitu mixmode,Bitu srcval)561 void XGA_DrawWaitSub(Bitu mixmode, Bitu srcval) {
562 	Bitu destval;
563 	Bitu dstdata;
564 	dstdata = XGA_GetPoint(xga.waitcmd.curx, xga.waitcmd.cury);
565 	destval = XGA_GetMixResult(mixmode, srcval, dstdata);
566 	//LOG_MSG("XGA: DrawPattern: Mixmode: %x srcval: %x", mixmode, srcval);
567 
568 	XGA_DrawPoint(xga.waitcmd.curx, xga.waitcmd.cury, destval);
569 	xga.waitcmd.curx++;
570 	xga.waitcmd.curx&=0x0fff;
571 	XGA_CheckX();
572 }
573 
XGA_DrawWait(Bitu val,Bitu len)574 void XGA_DrawWait(Bitu val, Bitu len) {
575 	if(!xga.waitcmd.wait) return;
576 	Bitu mixmode = (xga.pix_cntl >> 6) & 0x3;
577 	Bitu srcval;
578 	switch(xga.waitcmd.cmd) {
579 		case 2: /* Rectangle */
580 			switch(mixmode) {
581 				case 0x00: /* FOREMIX always used */
582 					mixmode = xga.foremix;
583 
584 /*					switch((mixmode >> 5) & 0x03) {
585 						case 0x00: // Src is background color
586 							srcval = xga.backcolor;
587 							break;
588 						case 0x01: // Src is foreground color
589 							srcval = xga.forecolor;
590 							break;
591 						case 0x02: // Src is pixel data from PIX_TRANS register
592 */
593 					if(((mixmode >> 5) & 0x03) != 0x2) {
594 						// those cases don't seem to occur
595 						LOG_MSG("XGA: unsupported drawwait operation");
596 						break;
597 					}
598 					switch(xga.waitcmd.buswidth) {
599 						case M_LIN8:		//  8 bit
600 							XGA_DrawWaitSub(mixmode, val);
601 							break;
602 						case 0x20 | M_LIN8: // 16 bit
603 							for(Bitu i = 0; i < len; i++) {
604 								XGA_DrawWaitSub(mixmode, (val>>(8*i))&0xff);
605 								if(xga.waitcmd.newline) break;
606 							}
607 							break;
608 						case 0x40 | M_LIN8: // 32 bit
609                             for(int i = 0; i < 4; i++)
610 								XGA_DrawWaitSub(mixmode, (val>>(8*i))&0xff);
611 							break;
612 						case (0x20 | M_LIN32):
613 							if(len!=4) { // Win 3.11 864 'hack?'
614 								if(xga.waitcmd.datasize == 0) {
615 									// set it up to wait for the next word
616 									xga.waitcmd.data = val;
617 									xga.waitcmd.datasize = 2;
618 									return;
619 								} else {
620 									srcval = (val<<16)|xga.waitcmd.data;
621 									xga.waitcmd.data = 0;
622 									xga.waitcmd.datasize = 0;
623 									XGA_DrawWaitSub(mixmode, srcval);
624 								}
625 								break;
626 							} // fall-through
627 						case 0x40 | M_LIN32: // 32 bit
628 							XGA_DrawWaitSub(mixmode, val);
629 							break;
630 						case 0x20 | M_LIN15: // 16 bit
631 						case 0x20 | M_LIN16: // 16 bit
632 							XGA_DrawWaitSub(mixmode, val);
633 							break;
634 						case 0x40 | M_LIN15: // 32 bit
635 						case 0x40 | M_LIN16: // 32 bit
636 							XGA_DrawWaitSub(mixmode, val&0xffff);
637 							if(!xga.waitcmd.newline)
638 								XGA_DrawWaitSub(mixmode, val>>16);
639 							break;
640 						default:
641 							// Let's hope they never show up ;)
642 							LOG_MSG("XGA: unsupported bpp / datawidth combination %x",
643 								xga.waitcmd.buswidth);
644 							break;
645 					};
646 					break;
647 
648 				case 0x02: // Data from PIX_TRANS selects the mix
649 					Bitu chunksize;
650 					Bitu chunks;
651 					switch(xga.waitcmd.buswidth&0x60) {
652 						case 0x0:
653 							chunksize=8;
654 							chunks=1;
655 							break;
656 						case 0x20: // 16 bit
657 							chunksize=16;
658 							if(len==4) chunks=2;
659 							else chunks = 1;
660 							break;
661 						case 0x40: // 32 bit
662 							chunksize=16;
663 							if(len==4) chunks=2;
664 							else chunks = 1;
665                            	break;
666 						case 0x60: // undocumented guess (but works)
667 							chunksize=8;
668 							chunks=4;
669 							break;
670 					}
671 
672 					for(Bitu k = 0; k < chunks; k++) { // chunks counter
673 						xga.waitcmd.newline = false;
674 						for(Bitu n = 0; n < chunksize; n++) { // pixels
675 							Bitu mixmode;
676 
677 							// This formula can rule the world ;)
678 							Bitu mask = 1 << ((((n&0xF8)+(8-(n&0x7)))-1)+chunksize*k);
679 							if(val&mask) mixmode = xga.foremix;
680 							else mixmode = xga.backmix;
681 
682 							switch((mixmode >> 5) & 0x03) {
683 								case 0x00: // Src is background color
684 									srcval = xga.backcolor;
685 									break;
686 								case 0x01: // Src is foreground color
687 									srcval = xga.forecolor;
688 									break;
689 								default:
690 									LOG_MSG("XGA: DrawBlitWait: Unsupported src %x",
691 										(mixmode >> 5) & 0x03);
692 									srcval=0;
693 									break;
694 							}
695                             XGA_DrawWaitSub(mixmode, srcval);
696 
697 							if((xga.waitcmd.cury<2048) &&
698 							  (xga.waitcmd.cury >= xga.waitcmd.y2)) {
699 								xga.waitcmd.wait = false;
700 								k=1000; // no more chunks
701 								break;
702 							}
703 							// next chunk goes to next line
704 							if(xga.waitcmd.newline) break;
705 						} // pixels loop
706 					} // chunks loop
707 					break;
708 
709 				default:
710 					LOG_MSG("XGA: DrawBlitWait: Unhandled mixmode: %d", mixmode);
711 					break;
712 			} // switch mixmode
713 			break;
714 		default:
715 			LOG_MSG("XGA: Unhandled draw command %x", xga.waitcmd.cmd);
716 			break;
717 	}
718 }
719 
XGA_BlitRect(Bitu val)720 void XGA_BlitRect(Bitu val) {
721 	Bit32u xat, yat;
722 	Bitu srcdata;
723 	Bitu dstdata;
724 
725 	Bitu srcval;
726 	Bitu destval;
727 
728 	Bits srcx, srcy, tarx, tary, dx, dy;
729 
730 	dx = -1;
731 	dy = -1;
732 
733 	if(((val >> 5) & 0x01) != 0) dx = 1;
734 	if(((val >> 7) & 0x01) != 0) dy = 1;
735 
736 	srcx = xga.curx;
737 	srcy = xga.cury;
738 	tarx = xga.destx;
739 	tary = xga.desty;
740 
741 	Bitu mixselect = (xga.pix_cntl >> 6) & 0x3;
742 	Bitu mixmode = 0x67; /* Source is bitmap data, mix mode is src */
743 	switch(mixselect) {
744 		case 0x00: /* Foreground mix is always used */
745 			mixmode = xga.foremix;
746 			break;
747 		case 0x02: /* CPU Data determines mix used */
748 			LOG_MSG("XGA: DrawPattern: Mixselect data from PIX_TRANS register");
749 			break;
750 		case 0x03: /* Video memory determines mix */
751 			//LOG_MSG("XGA: Srcdata: %x, Forecolor %x, Backcolor %x, Foremix: %x Backmix: %x", srcdata, xga.forecolor, xga.backcolor, xga.foremix, xga.backmix);
752 			break;
753 		default:
754 			LOG_MSG("XGA: BlitRect: Unknown mix select register");
755 			break;
756 	}
757 
758 
759 	/* Copy source to video ram */
760 	for(yat=0;yat<=xga.MIPcount ;yat++) {
761 		srcx = xga.curx;
762 		tarx = xga.destx;
763 
764 		for(xat=0;xat<=xga.MAPcount;xat++) {
765 			srcdata = XGA_GetPoint(srcx, srcy);
766 			dstdata = XGA_GetPoint(tarx, tary);
767 
768 			if(mixselect == 0x3) {
769 				if(srcdata == xga.forecolor) {
770 					mixmode = xga.foremix;
771 				} else {
772 					if(srcdata == xga.backcolor) {
773 						mixmode = xga.backmix;
774 					} else {
775 						/* Best guess otherwise */
776 						mixmode = 0x67; /* Source is bitmap data, mix mode is src */
777 					}
778 				}
779 			}
780 
781 			switch((mixmode >> 5) & 0x03) {
782 				case 0x00: /* Src is background color */
783 					srcval = xga.backcolor;
784 					break;
785 				case 0x01: /* Src is foreground color */
786 					srcval = xga.forecolor;
787 					break;
788 				case 0x02: /* Src is pixel data from PIX_TRANS register */
789 					LOG_MSG("XGA: DrawPattern: Wants data from PIX_TRANS register");
790 					break;
791 				case 0x03: /* Src is bitmap data */
792 					srcval = srcdata;
793 					break;
794 				default:
795 					LOG_MSG("XGA: DrawPattern: Shouldn't be able to get here!");
796 					srcval = 0;
797 					break;
798 			}
799 
800 			destval = XGA_GetMixResult(mixmode, srcval, dstdata);
801 			//LOG_MSG("XGA: DrawPattern: Mixmode: %x Mixselect: %x", mixmode, mixselect);
802 
803 			XGA_DrawPoint(tarx, tary, destval);
804 
805 			srcx += dx;
806 			tarx += dx;
807 		}
808 		srcy += dy;
809 		tary += dy;
810 	}
811 }
812 
XGA_DrawPattern(Bitu val)813 void XGA_DrawPattern(Bitu val) {
814 	Bitu srcdata;
815 	Bitu dstdata;
816 
817 	Bitu srcval;
818 	Bitu destval;
819 
820 	Bits xat, yat, srcx, srcy, tarx, tary, dx, dy;
821 
822 	dx = -1;
823 	dy = -1;
824 
825 	if(((val >> 5) & 0x01) != 0) dx = 1;
826 	if(((val >> 7) & 0x01) != 0) dy = 1;
827 
828 	srcx = xga.curx;
829 	srcy = xga.cury;
830 
831 	tary = xga.desty;
832 
833 	Bitu mixselect = (xga.pix_cntl >> 6) & 0x3;
834 	Bitu mixmode = 0x67; /* Source is bitmap data, mix mode is src */
835 	switch(mixselect) {
836 		case 0x00: /* Foreground mix is always used */
837 			mixmode = xga.foremix;
838 			break;
839 		case 0x02: /* CPU Data determines mix used */
840 			LOG_MSG("XGA: DrawPattern: Mixselect data from PIX_TRANS register");
841 			break;
842 		case 0x03: /* Video memory determines mix */
843 			//LOG_MSG("XGA: Pixctl: %x, Srcdata: %x, Forecolor %x, Backcolor %x, Foremix: %x Backmix: %x",xga.pix_cntl, srcdata, xga.forecolor, xga.backcolor, xga.foremix, xga.backmix);
844 			break;
845 		default:
846 			LOG_MSG("XGA: DrawPattern: Unknown mix select register");
847 			break;
848 	}
849 
850 	for(yat=0;yat<=xga.MIPcount;yat++) {
851 		tarx = xga.destx;
852 		for(xat=0;xat<=xga.MAPcount;xat++) {
853 
854 			srcdata = XGA_GetPoint(srcx + (tarx & 0x7), srcy + (tary & 0x7));
855 			//LOG_MSG("patternpoint (%3d/%3d)v%x",srcx + (tarx & 0x7), srcy + (tary & 0x7),srcdata);
856 			dstdata = XGA_GetPoint(tarx, tary);
857 
858 
859 			if(mixselect == 0x3) {
860 				// TODO lots of guessing here but best results this way
861 				/*if(srcdata == xga.forecolor)*/ mixmode = xga.foremix;
862 				// else
863 				if(srcdata == xga.backcolor || srcdata == 0)
864 					mixmode = xga.backmix;
865 			}
866 
867 			switch((mixmode >> 5) & 0x03) {
868 				case 0x00: /* Src is background color */
869 					srcval = xga.backcolor;
870 					break;
871 				case 0x01: /* Src is foreground color */
872 					srcval = xga.forecolor;
873 					break;
874 				case 0x02: /* Src is pixel data from PIX_TRANS register */
875 					LOG_MSG("XGA: DrawPattern: Wants data from PIX_TRANS register");
876 					break;
877 				case 0x03: /* Src is bitmap data */
878 					srcval = srcdata;
879 					break;
880 				default:
881 					LOG_MSG("XGA: DrawPattern: Shouldn't be able to get here!");
882 					srcval = 0;
883 					break;
884 			}
885 
886 			destval = XGA_GetMixResult(mixmode, srcval, dstdata);
887 
888 			XGA_DrawPoint(tarx, tary, destval);
889 
890 			tarx += dx;
891 		}
892 		tary += dy;
893 	}
894 }
895 
XGA_DrawCmd(Bitu val,Bitu len)896 void XGA_DrawCmd(Bitu val, Bitu len) {
897 	Bit16u cmd;
898 	cmd = val >> 13;
899 #if XGA_SHOW_COMMAND_TRACE == 1
900 	//LOG_MSG("XGA: Draw command %x", cmd);
901 #endif
902 	xga.curcommand = val;
903 	switch(cmd) {
904 		case 1: /* Draw line */
905 			if((val & 0x100) == 0) {
906 				if((val & 0x8) == 0) {
907 #if XGA_SHOW_COMMAND_TRACE == 1
908 					LOG_MSG("XGA: Drawing Bresenham line");
909 #endif
910                     XGA_DrawLineBresenham(val);
911 				} else {
912 #if XGA_SHOW_COMMAND_TRACE == 1
913 					LOG_MSG("XGA: Drawing vector line");
914 #endif
915 					XGA_DrawLineVector(val);
916 				}
917 			} else {
918 				LOG_MSG("XGA: Wants line drawn from PIX_TRANS register!");
919 			}
920 			break;
921 		case 2: /* Rectangle fill */
922 			if((val & 0x100) == 0) {
923 				xga.waitcmd.wait = false;
924 #if XGA_SHOW_COMMAND_TRACE == 1
925 				LOG_MSG("XGA: Draw immediate rect: xy(%3d/%3d), len(%3d/%3d)",
926 					xga.curx,xga.cury,xga.MAPcount,xga.MIPcount);
927 #endif
928 				XGA_DrawRectangle(val);
929 
930 			} else {
931 
932 				xga.waitcmd.newline = true;
933 				xga.waitcmd.wait = true;
934 				xga.waitcmd.curx = xga.curx;
935 				xga.waitcmd.cury = xga.cury;
936 				xga.waitcmd.x1 = xga.curx;
937 				xga.waitcmd.y1 = xga.cury;
938 				xga.waitcmd.x2 = (Bit16u)((xga.curx + xga.MAPcount)&0x0fff);
939 				xga.waitcmd.y2 = (Bit16u)((xga.cury + xga.MIPcount + 1)&0x0fff);
940 				xga.waitcmd.sizex = xga.MAPcount;
941 				xga.waitcmd.sizey = xga.MIPcount + 1;
942 				xga.waitcmd.cmd = 2;
943 				xga.waitcmd.buswidth = vga.mode | ((val&0x600) >> 4);
944 				xga.waitcmd.data = 0;
945 				xga.waitcmd.datasize = 0;
946 
947 #if XGA_SHOW_COMMAND_TRACE == 1
948 				LOG_MSG("XGA: Draw wait rect, w/h(%3d/%3d), x/y1(%3d/%3d), x/y2(%3d/%3d), %4x",
949 					xga.MAPcount+1, xga.MIPcount+1,xga.curx,xga.cury,
950 					(xga.curx + xga.MAPcount)&0x0fff,
951 					(xga.cury + xga.MIPcount + 1)&0x0fff,val&0xffff);
952 #endif
953 
954 			}
955 			break;
956 		case 6: /* BitBLT */
957 #if XGA_SHOW_COMMAND_TRACE == 1
958 			LOG_MSG("XGA: Blit Rect");
959 #endif
960 			XGA_BlitRect(val);
961 			break;
962 		case 7: /* Pattern fill */
963 #if XGA_SHOW_COMMAND_TRACE == 1
964 			LOG_MSG("XGA: Pattern fill: src(%3d/%3d), dest(%3d/%3d), fill(%3d/%3d)",
965 				xga.curx,xga.cury,xga.destx,xga.desty,xga.MAPcount,xga.MIPcount);
966 #endif
967 			XGA_DrawPattern(val);
968 			break;
969 		default:
970 			LOG_MSG("XGA: Unhandled draw command %x", cmd);
971 			break;
972 	}
973 }
974 
XGA_SetDualReg(Bit32u & reg,Bitu val)975 void XGA_SetDualReg(Bit32u& reg, Bitu val) {
976 	switch(XGA_COLOR_MODE) {
977 	case M_LIN8:
978 		reg = (Bit8u)(val&0xff); break;
979 	case M_LIN15:
980 	case M_LIN16:
981 		reg = (Bit16u)(val&0xffff); break;
982 	case M_LIN32:
983 		if (xga.control1 & 0x200)
984 			reg = val;
985 		else if (xga.control1 & 0x10)
986 			reg = (reg&0x0000ffff)|(val<<16);
987 		else
988 			reg = (reg&0xffff0000)|(val&0x0000ffff);
989 		xga.control1 ^= 0x10;
990 		break;
991 	}
992 }
993 
XGA_GetDualReg(Bit32u reg)994 Bitu XGA_GetDualReg(Bit32u reg) {
995 	switch(XGA_COLOR_MODE) {
996 	case M_LIN8:
997 		return (Bit8u)(reg&0xff);
998 	case M_LIN15: case M_LIN16:
999 		return (Bit16u)(reg&0xffff);
1000 	case M_LIN32:
1001 		if (xga.control1 & 0x200) return reg;
1002 		xga.control1 ^= 0x10;
1003 		if (xga.control1 & 0x10) return reg&0x0000ffff;
1004 		else return reg>>16;
1005 	}
1006 	return 0;
1007 }
1008 
1009 extern Bitu vga_read_p3da(Bitu port,Bitu iolen);
1010 
1011 extern void vga_write_p3d4(Bitu port,Bitu val,Bitu iolen);
1012 extern Bitu vga_read_p3d4(Bitu port,Bitu iolen);
1013 
1014 extern void vga_write_p3d5(Bitu port,Bitu val,Bitu iolen);
1015 extern Bitu vga_read_p3d5(Bitu port,Bitu iolen);
1016 
XGA_Write(Bitu port,Bitu val,Bitu len)1017 void XGA_Write(Bitu port, Bitu val, Bitu len) {
1018 //	LOG_MSG("XGA: Write to port %x, val %8x, len %x", port,val, len);
1019 
1020 	switch(port) {
1021 		case 0x8100:// drawing control: row (low word), column (high word)
1022 					// "CUR_X" and "CUR_Y" (see PORT 82E8h,PORT 86E8h)
1023 			xga.cury = val & 0x0fff;
1024 			if(len==4) xga.curx = (val>>16)&0x0fff;
1025 			break;
1026 		case 0x8102:
1027 			xga.curx = val& 0x0fff;
1028 			break;
1029 
1030 		case 0x8108:// DWORD drawing control: destination Y and axial step
1031 					// constant (low word), destination X and axial step
1032 					// constant (high word) (see PORT 8AE8h,PORT 8EE8h)
1033 			xga.desty = val&0x3FFF;
1034 			if(len==4) xga.destx = (val>>16)&0x3fff;
1035 			break;
1036 		case 0x810a:
1037 			xga.destx = val&0x3fff;
1038 			break;
1039 		case 0x8110: // WORD error term (see PORT 92E8h)
1040 			xga.ErrTerm = val&0x3FFF;
1041 			break;
1042 
1043 		case 0x8120: // packed MMIO: DWORD background color (see PORT A2E8h)
1044 			xga.backcolor = val;
1045 			break;
1046 		case 0x8124: // packed MMIO: DWORD foreground color (see PORT A6E8h)
1047 			xga.forecolor = val;
1048 			break;
1049 		case 0x8128: // DWORD	write mask (see PORT AAE8h)
1050 			xga.writemask = val;
1051 			break;
1052 		case 0x812C: // DWORD	read mask (see PORT AEE8h)
1053 			xga.readmask = val;
1054 			break;
1055 		case 0x8134: // packed MMIO: DWORD	background mix (low word) and
1056 					 // foreground mix (high word)	(see PORT B6E8h,PORT BAE8h)
1057 			xga.backmix = val&0xFFFF;
1058 			if(len==4) xga.foremix = (val>>16);
1059 			break;
1060 		case 0x8136:
1061 			xga.foremix = val;
1062 			break;
1063 		case 0x8138:// DWORD top scissors (low word) and left scissors (high
1064 					// word) (see PORT BEE8h,#P1047)
1065 			xga.scissors.y1=val&0x0fff;
1066 			if(len==4) xga.scissors.x1 = (val>>16)&0x0fff;
1067 			break;
1068 		case 0x813a:
1069 			xga.scissors.x1 = val&0x0fff;
1070 			break;
1071 		case 0x813C:// DWORD bottom scissors (low word) and right scissors
1072 					// (high word) (see PORT BEE8h,#P1047)
1073 			xga.scissors.y2=val&0x0fff;
1074 			if(len==4) xga.scissors.x2 = (val>>16)&0x0fff;
1075 			break;
1076 		case 0x813e:
1077 			xga.scissors.x2 = val&0x0fff;
1078 			break;
1079 
1080 		case 0x8140:// DWORD data manipulation control (low word) and
1081 					// miscellaneous 2 (high word) (see PORT BEE8h,#P1047)
1082 			xga.pix_cntl=val&0xFFFF;
1083 			if(len==4) xga.control2=(val>>16)&0x0fff;
1084 			break;
1085 		case 0x8144:// DWORD miscellaneous (low word) and read register select
1086 					// (high word)(see PORT BEE8h,#P1047)
1087 			xga.control1=val&0xffff;
1088 			if(len==4)xga.read_sel=(val>>16)&0x7;
1089 			break;
1090 		case 0x8148:// DWORD minor axis pixel count (low word) and major axis
1091 					// pixel count (high word) (see PORT BEE8h,#P1047,PORT 96E8h)
1092 			xga.MIPcount = val&0x0fff;
1093 			if(len==4) xga.MAPcount = (val>>16)&0x0fff;
1094 			break;
1095 		case 0x814a:
1096 			xga.MAPcount = val&0x0fff;
1097 			break;
1098 		case 0x92e8:
1099 			xga.ErrTerm = val&0x3FFF;
1100 			break;
1101 		case 0x96e8:
1102 			xga.MAPcount = val&0x0fff;
1103 			break;
1104 		case 0x9ae8:
1105 		case 0x8118: // Trio64V+ packed MMIO
1106 			XGA_DrawCmd(val, len);
1107 			break;
1108 		case 0xa2e8:
1109 			XGA_SetDualReg(xga.backcolor, val);
1110 			break;
1111 		case 0xa6e8:
1112 			XGA_SetDualReg(xga.forecolor, val);
1113 			break;
1114 		case 0xaae8:
1115 			XGA_SetDualReg(xga.writemask, val);
1116 			break;
1117 		case 0xaee8:
1118 			XGA_SetDualReg(xga.readmask, val);
1119 			break;
1120 		case 0x82e8:
1121 			xga.cury = val&0x0fff;
1122 			break;
1123 		case 0x86e8:
1124 			xga.curx = val&0x0fff;
1125 			break;
1126 		case 0x8ae8:
1127 			xga.desty = val&0x3fff;
1128 			break;
1129 		case 0x8ee8:
1130 			xga.destx = val&0x3fff;
1131 			break;
1132 		case 0xb2e8:
1133 			LOG_MSG("COLOR_CMP not implemented");
1134 			break;
1135 		case 0xb6e8:
1136 			xga.backmix = val;
1137 			break;
1138 		case 0xbae8:
1139 			xga.foremix = val;
1140 			break;
1141 		case 0xbee8:
1142 			XGA_Write_Multifunc(val, len);
1143 			break;
1144 		case 0xe2e8:
1145 			xga.waitcmd.newline = false;
1146 			XGA_DrawWait(val, len);
1147 			break;
1148 		case 0x83d4:
1149 			if(len==1) vga_write_p3d4(0,val,1);
1150 			else if(len==2) {
1151 				vga_write_p3d4(0,val&0xff,1);
1152 				vga_write_p3d5(0,val>>8,1);
1153 			}
1154 			else E_Exit("unimplemented XGA MMIO");
1155 			break;
1156 		case 0x83d5:
1157 			if(len==1) vga_write_p3d5(0,val,1);
1158 			else E_Exit("unimplemented XGA MMIO");
1159 			break;
1160 		default:
1161 			if(port <= 0x4000) {
1162 				//LOG_MSG("XGA: Wrote to port %4x with %08x, len %x", port, val, len);
1163 				xga.waitcmd.newline = false;
1164 				XGA_DrawWait(val, len);
1165 
1166 			}
1167 			else LOG_MSG("XGA: Wrote to port %x with %x, len %x", port, val, len);
1168 			break;
1169 	}
1170 }
1171 
XGA_Read(Bitu port,Bitu len)1172 Bitu XGA_Read(Bitu port, Bitu len) {
1173 	switch(port) {
1174 		case 0x8118:
1175 		case 0x9ae8:
1176 			return 0x400; // nothing busy
1177 			break;
1178 		case 0x81ec: // S3 video data processor
1179 			return 0x00007000;
1180 			break;
1181 		case 0x83da:
1182 			{
1183 				Bits delaycyc = CPU_CycleMax/5000;
1184 				if(GCC_UNLIKELY(CPU_Cycles < 3*delaycyc)) delaycyc = 0;
1185 				CPU_Cycles -= delaycyc;
1186 				CPU_IODelayRemoved += delaycyc;
1187 				return vga_read_p3da(0,0);
1188 				break;
1189 			}
1190 		case 0x83d4:
1191 			if(len==1) return vga_read_p3d4(0,0);
1192 			else E_Exit("unimplemented XGA MMIO");
1193 			break;
1194 		case 0x83d5:
1195 			if(len==1) return vga_read_p3d5(0,0);
1196 			else E_Exit("unimplemented XGA MMIO");
1197 			break;
1198 		case 0x9ae9:
1199 			if(xga.waitcmd.wait) return 0x4;
1200 			else return 0x0;
1201 		case 0xbee8:
1202 			return XGA_Read_Multifunc();
1203 		case 0xa2e8:
1204 			return XGA_GetDualReg(xga.backcolor);
1205 			break;
1206 		case 0xa6e8:
1207 			return XGA_GetDualReg(xga.forecolor);
1208 			break;
1209 		case 0xaae8:
1210 			return XGA_GetDualReg(xga.writemask);
1211 			break;
1212 		case 0xaee8:
1213 			return XGA_GetDualReg(xga.readmask);
1214 			break;
1215 		default:
1216 			//LOG_MSG("XGA: Read from port %x, len %x", port, len);
1217 			break;
1218 	}
1219 	return 0xffffffff;
1220 }
1221 
VGA_SetupXGA(void)1222 void VGA_SetupXGA(void) {
1223 	if (!IS_VGA_ARCH) return;
1224 
1225 	memset(&xga, 0, sizeof(XGAStatus));
1226 
1227 	xga.scissors.y1 = 0;
1228 	xga.scissors.x1 = 0;
1229 	xga.scissors.y2 = 0xFFF;
1230 	xga.scissors.x2 = 0xFFF;
1231 
1232 	IO_RegisterWriteHandler(0x42e8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1233 	IO_RegisterReadHandler(0x42e8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1234 
1235 	IO_RegisterWriteHandler(0x46e8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1236 	IO_RegisterWriteHandler(0x4ae8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1237 
1238 	IO_RegisterWriteHandler(0x82e8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1239 	IO_RegisterReadHandler(0x82e8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1240 	IO_RegisterWriteHandler(0x82e9,&XGA_Write,IO_MB | IO_MW | IO_MD);
1241 	IO_RegisterReadHandler(0x82e9,&XGA_Read,IO_MB | IO_MW | IO_MD);
1242 
1243 	IO_RegisterWriteHandler(0x86e8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1244 	IO_RegisterReadHandler(0x86e8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1245 	IO_RegisterWriteHandler(0x86e9,&XGA_Write,IO_MB | IO_MW | IO_MD);
1246 	IO_RegisterReadHandler(0x86e9,&XGA_Read,IO_MB | IO_MW | IO_MD);
1247 
1248 	IO_RegisterWriteHandler(0x8ae8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1249 	IO_RegisterReadHandler(0x8ae8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1250 
1251 	IO_RegisterWriteHandler(0x8ee8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1252 	IO_RegisterReadHandler(0x8ee8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1253 	IO_RegisterWriteHandler(0x8ee9,&XGA_Write,IO_MB | IO_MW | IO_MD);
1254 	IO_RegisterReadHandler(0x8ee9,&XGA_Read,IO_MB | IO_MW | IO_MD);
1255 
1256 	IO_RegisterWriteHandler(0x92e8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1257 	IO_RegisterReadHandler(0x92e8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1258 	IO_RegisterWriteHandler(0x92e9,&XGA_Write,IO_MB | IO_MW | IO_MD);
1259 	IO_RegisterReadHandler(0x92e9,&XGA_Read,IO_MB | IO_MW | IO_MD);
1260 
1261 	IO_RegisterWriteHandler(0x96e8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1262 	IO_RegisterReadHandler(0x96e8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1263 	IO_RegisterWriteHandler(0x96e9,&XGA_Write,IO_MB | IO_MW | IO_MD);
1264 	IO_RegisterReadHandler(0x96e9,&XGA_Read,IO_MB | IO_MW | IO_MD);
1265 
1266 	IO_RegisterWriteHandler(0x9ae8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1267 	IO_RegisterReadHandler(0x9ae8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1268 	IO_RegisterWriteHandler(0x9ae9,&XGA_Write,IO_MB | IO_MW | IO_MD);
1269 	IO_RegisterReadHandler(0x9ae9,&XGA_Read,IO_MB | IO_MW | IO_MD);
1270 
1271 	IO_RegisterWriteHandler(0x9ee8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1272 	IO_RegisterReadHandler(0x9ee8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1273 	IO_RegisterWriteHandler(0x9ee9,&XGA_Write,IO_MB | IO_MW | IO_MD);
1274 	IO_RegisterReadHandler(0x9ee9,&XGA_Read,IO_MB | IO_MW | IO_MD);
1275 
1276 	IO_RegisterWriteHandler(0xa2e8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1277 	IO_RegisterReadHandler(0xa2e8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1278 
1279 	IO_RegisterWriteHandler(0xa6e8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1280 	IO_RegisterReadHandler(0xa6e8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1281 	IO_RegisterWriteHandler(0xa6e9,&XGA_Write,IO_MB | IO_MW | IO_MD);
1282 	IO_RegisterReadHandler(0xa6e9,&XGA_Read,IO_MB | IO_MW | IO_MD);
1283 
1284 	IO_RegisterWriteHandler(0xaae8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1285 	IO_RegisterReadHandler(0xaae8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1286 	IO_RegisterWriteHandler(0xaae9,&XGA_Write,IO_MB | IO_MW | IO_MD);
1287 	IO_RegisterReadHandler(0xaae9,&XGA_Read,IO_MB | IO_MW | IO_MD);
1288 
1289 	IO_RegisterWriteHandler(0xaee8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1290 	IO_RegisterReadHandler(0xaee8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1291 	IO_RegisterWriteHandler(0xaee9,&XGA_Write,IO_MB | IO_MW | IO_MD);
1292 	IO_RegisterReadHandler(0xaee9,&XGA_Read,IO_MB | IO_MW | IO_MD);
1293 
1294 	IO_RegisterWriteHandler(0xb2e8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1295 	IO_RegisterReadHandler(0xb2e8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1296 	IO_RegisterWriteHandler(0xb2e9,&XGA_Write,IO_MB | IO_MW | IO_MD);
1297 	IO_RegisterReadHandler(0xb2e9,&XGA_Read,IO_MB | IO_MW | IO_MD);
1298 
1299 	IO_RegisterWriteHandler(0xb6e8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1300 	IO_RegisterReadHandler(0xb6e8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1301 
1302 	IO_RegisterWriteHandler(0xbee8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1303 	IO_RegisterReadHandler(0xbee8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1304 	IO_RegisterWriteHandler(0xbee9,&XGA_Write,IO_MB | IO_MW | IO_MD);
1305 	IO_RegisterReadHandler(0xbee9,&XGA_Read,IO_MB | IO_MW | IO_MD);
1306 
1307 	IO_RegisterWriteHandler(0xbae8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1308 	IO_RegisterReadHandler(0xbae8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1309 	IO_RegisterWriteHandler(0xbae9,&XGA_Write,IO_MB | IO_MW | IO_MD);
1310 	IO_RegisterReadHandler(0xbae9,&XGA_Read,IO_MB | IO_MW | IO_MD);
1311 
1312 	IO_RegisterWriteHandler(0xe2e8,&XGA_Write,IO_MB | IO_MW | IO_MD);
1313 	IO_RegisterReadHandler(0xe2e8,&XGA_Read,IO_MB | IO_MW | IO_MD);
1314 
1315 	IO_RegisterWriteHandler(0xe2e0,&XGA_Write,IO_MB | IO_MW | IO_MD);
1316 	IO_RegisterReadHandler(0xe2e0,&XGA_Read,IO_MB | IO_MW | IO_MD);
1317 
1318 	IO_RegisterWriteHandler(0xe2ea,&XGA_Write,IO_MB | IO_MW | IO_MD);
1319 	IO_RegisterReadHandler(0xe2ea,&XGA_Read,IO_MB | IO_MW | IO_MD);
1320 }
1321