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