DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/ints/int10.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #include "dosbox.h"
00021 #include "control.h"
00022 #include "mem.h"
00023 #include "callback.h"
00024 #include "regs.h"
00025 #include "inout.h"
00026 #include "int10.h"
00027 #include "mouse.h"
00028 #include "setup.h"
00029 
00030 Int10Data int10;
00031 static Bitu call_10 = 0;
00032 static bool warned_ff=false;
00033 
00034 extern bool enable_vga_8bit_dac;
00035 extern bool vga_8bit_dac;
00036 
00037 Bitu INT10_Handler(void) {
00038         // NTS: We do have to check the "current video mode" from the BIOS data area every call.
00039         //      Some OSes like Windows 95 rely on overwriting the "current video mode" byte in
00040         //      the BIOS data area to play tricks with the BIOS. If we don't call this, tricks
00041         //      like the Windows 95 boot logo or INT 10h virtualization in Windows 3.1/9x/ME
00042         //      within the DOS "box" will not work properly.
00043         INT10_SetCurMode();
00044 
00045         switch (reg_ah) {
00046         case 0x00:                                                              /* Set VideoMode */
00047                 Mouse_BeforeNewVideoMode(true);
00048                 INT10_SetVideoMode(reg_al);
00049                 Mouse_AfterNewVideoMode(true);
00050                 break;
00051         case 0x01:                                                              /* Set TextMode Cursor Shape */
00052                 INT10_SetCursorShape(reg_ch,reg_cl);
00053                 break;
00054         case 0x02:                                                              /* Set Cursor Pos */
00055                 INT10_SetCursorPos(reg_dh,reg_dl,reg_bh);
00056                 break;
00057         case 0x03:                                                              /* get Cursor Pos and Cursor Shape*/
00058 //              reg_ah=0;
00059                 reg_dl=CURSOR_POS_COL(reg_bh);
00060                 reg_dh=CURSOR_POS_ROW(reg_bh);
00061                 reg_cx=real_readw(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE);
00062                 break;
00063         case 0x04:                                                              /* read light pen pos YEAH RIGHT */
00064                 /* Light pen is not supported */
00065                 reg_ax=0;
00066                 break;
00067         case 0x05:                                                              /* Set Active Page */
00068                 if ((reg_al & 0x80) && IS_TANDY_ARCH) {
00069                         Bit8u crtcpu=real_readb(BIOSMEM_SEG, BIOSMEM_CRTCPU_PAGE);              
00070                         switch (reg_al) {
00071                         case 0x80:
00072                                 reg_bh=crtcpu & 7;
00073                                 reg_bl=(crtcpu >> 3) & 0x7;
00074                                 break;
00075                         case 0x81:
00076                                 crtcpu=(crtcpu & 0xc7) | ((reg_bl & 7) << 3);
00077                                 break;
00078                         case 0x82:
00079                                 crtcpu=(crtcpu & 0xf8) | (reg_bh & 7);
00080                                 break;
00081                         case 0x83:
00082                                 crtcpu=(crtcpu & 0xc0) | (reg_bh & 7) | ((reg_bl & 7) << 3);
00083                                 break;
00084                         }
00085                         if (machine==MCH_PCJR) {
00086                                 /* always return graphics mapping, even for invalid values of AL */
00087                                 reg_bh=crtcpu & 7;
00088                                 reg_bl=(crtcpu >> 3) & 0x7;
00089                         }
00090                         IO_WriteB(0x3df,crtcpu);
00091                         real_writeb(BIOSMEM_SEG, BIOSMEM_CRTCPU_PAGE,crtcpu);
00092                 }
00093                 else INT10_SetActivePage(reg_al);
00094                 break;  
00095         case 0x06:                                                              /* Scroll Up */
00096                 INT10_ScrollWindow(reg_ch,reg_cl,reg_dh,reg_dl,-(Bit8s)reg_al,reg_bh,0xFF);
00097                 break;
00098         case 0x07:                                                              /* Scroll Down */
00099                 INT10_ScrollWindow(reg_ch,reg_cl,reg_dh,reg_dl,(Bit8s)reg_al,reg_bh,0xFF);
00100                 break;
00101         case 0x08:                                                              /* Read character & attribute at cursor */
00102                 INT10_ReadCharAttr(&reg_ax,reg_bh);
00103                 break;                                          
00104         case 0x09:                                                              /* Write Character & Attribute at cursor CX times */
00105                 if (real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)==0x11)
00106                         INT10_WriteChar(reg_al,(reg_bl&0x80)|0x3f,reg_bh,reg_cx,true);
00107                 else INT10_WriteChar(reg_al,reg_bl,reg_bh,reg_cx,true);
00108                 break;
00109         case 0x0A:                                                              /* Write Character at cursor CX times */
00110                 INT10_WriteChar(reg_al,reg_bl,reg_bh,reg_cx,false);
00111                 break;
00112         case 0x0B:                                                              /* Set Background/Border Colour & Set Palette*/
00113                 switch (reg_bh) {
00114                 case 0x00:              //Background/Border color
00115                         INT10_SetBackgroundBorder(reg_bl);
00116                         break;
00117                 case 0x01:              //Set color Select
00118                 default:
00119                         INT10_SetColorSelect(reg_bl);
00120                         break;
00121                 }
00122                 break;
00123         case 0x0C:                                                              /* Write Graphics Pixel */
00124                 INT10_PutPixel(reg_cx,reg_dx,reg_bh,reg_al);
00125                 break;
00126         case 0x0D:                                                              /* Read Graphics Pixel */
00127                 INT10_GetPixel(reg_cx,reg_dx,reg_bh,&reg_al);
00128                 break;
00129         case 0x0E:                                                              /* Teletype OutPut */
00130                 INT10_TeletypeOutput(reg_al,reg_bl);
00131                 break;
00132         case 0x0F:                                                              /* Get videomode */
00133                 reg_bh=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
00134                 reg_al=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)|(real_readb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)&0x80);
00135                 reg_ah=(Bit8u)real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS);
00136                 break;                                  
00137         case 0x10:                                                              /* Palette functions */
00138         if (machine==MCH_MCGA) {
00139             if (!(reg_al == 0x10 || reg_al == 0x12 || reg_al == 0x15 || reg_al == 0x17 || reg_al == 0x18 || reg_al == 0x19))
00140                 break;
00141         }
00142         else if (machine==MCH_PCJR) {
00143             if (reg_al>0x02) /* "Looking at the PCjr tech ref page A-61, ... the BIOS listing stops at subfunction 2." */
00144                 break;
00145         }
00146         else {
00147             if (!IS_EGAVGA_ARCH && (reg_al>0x02)) break;
00148             else if (!IS_VGA_ARCH && (reg_al>0x03)) break;
00149         }
00150 
00151                 switch (reg_al) {
00152                 case 0x00:                                                      /* SET SINGLE PALETTE REGISTER */
00153                         INT10_SetSinglePaletteRegister(reg_bl,reg_bh);
00154                         break;
00155                 case 0x01:                                                      /* SET BORDER (OVERSCAN) COLOR*/
00156                         INT10_SetOverscanBorderColor(reg_bh);
00157                         break;
00158                 case 0x02:                                                      /* SET ALL PALETTE REGISTERS */
00159                         INT10_SetAllPaletteRegisters(SegPhys(es)+reg_dx);
00160                         break;
00161                 case 0x03:                                                      /* TOGGLE INTENSITY/BLINKING BIT */
00162                         INT10_ToggleBlinkingBit(reg_bl);
00163                         break;
00164                 case 0x07:                                                      /* GET SINGLE PALETTE REGISTER */
00165                         INT10_GetSinglePaletteRegister(reg_bl,&reg_bh);
00166                         break;
00167                 case 0x08:                                                      /* READ OVERSCAN (BORDER COLOR) REGISTER */
00168                         INT10_GetOverscanBorderColor(&reg_bh);
00169                         break;
00170                 case 0x09:                                                      /* READ ALL PALETTE REGISTERS AND OVERSCAN REGISTER */
00171                         INT10_GetAllPaletteRegisters(SegPhys(es)+reg_dx);
00172                         break;
00173                 case 0x10:                                                      /* SET INDIVIDUAL DAC REGISTER */
00174                         INT10_SetSingleDACRegister(reg_bl,reg_dh,reg_ch,reg_cl);
00175                         break;
00176                 case 0x12:                                                      /* SET BLOCK OF DAC REGISTERS */
00177                         INT10_SetDACBlock(reg_bx,reg_cx,SegPhys(es)+reg_dx);
00178                         break;
00179                 case 0x13:                                                      /* SELECT VIDEO DAC COLOR PAGE */
00180                         INT10_SelectDACPage(reg_bl,reg_bh);
00181                         break;
00182                 case 0x15:                                                      /* GET INDIVIDUAL DAC REGISTER */
00183                         INT10_GetSingleDACRegister(reg_bl,&reg_dh,&reg_ch,&reg_cl);
00184                         break;
00185                 case 0x17:                                                      /* GET BLOCK OF DAC REGISTER */
00186                         INT10_GetDACBlock(reg_bx,reg_cx,SegPhys(es)+reg_dx);
00187                         break;
00188                 case 0x18:                                                      /* undocumented - SET PEL MASK */
00189                         INT10_SetPelMask(reg_bl);
00190                         break;
00191                 case 0x19:                                                      /* undocumented - GET PEL MASK */
00192                         INT10_GetPelMask(reg_bl);
00193                         reg_bh=0;       // bx for get mask
00194                         break;
00195                 case 0x1A:                                                      /* GET VIDEO DAC COLOR PAGE */
00196                         INT10_GetDACPage(&reg_bl,&reg_bh);
00197                         break;
00198                 case 0x1B:                                                      /* PERFORM GRAY-SCALE SUMMING */
00199                         INT10_PerformGrayScaleSumming(reg_bx,reg_cx);
00200                         break;
00201                 case 0xF0: case 0xF1: case 0xF2: /* ET4000 Sierra HiColor DAC support */
00202                         if (svgaCard == SVGA_TsengET4K && svga.int10_extensions) {
00203                                 svga.int10_extensions();
00204                                 break;
00205                         }
00206                 default:
00207                         LOG(LOG_INT10,LOG_ERROR)("Function 10:Unhandled EGA/VGA Palette Function %2X",reg_al);
00208                         break;
00209                 }
00210                 break;
00211         case 0x11:                                                              /* Character generator functions */
00212         if (machine==MCH_MCGA) {
00213             if (!(reg_al == 0x24 || reg_al == 0x30))
00214                 break;
00215         }
00216         else {
00217             if (!IS_EGAVGA_ARCH)
00218                 break;
00219         }
00220 
00221                 if ((reg_al&0xf0)==0x10) Mouse_BeforeNewVideoMode(false);
00222                 switch (reg_al) {
00223 /* Textmode calls */
00224                 case 0x00:                      /* Load user font */
00225                 case 0x10:
00226                         INT10_LoadFont(SegPhys(es)+reg_bp,reg_al==0x10,reg_cx,reg_dx,reg_bl&0x7f,reg_bh);
00227                         break;
00228                 case 0x01:                      /* Load 8x14 font */
00229                 case 0x11:
00230                         INT10_LoadFont(Real2Phys(int10.rom.font_14),reg_al==0x11,256,0,reg_bl&0x7f,14);
00231                         break;
00232                 case 0x02:                      /* Load 8x8 font */
00233                 case 0x12:
00234                         INT10_LoadFont(Real2Phys(int10.rom.font_8_first),reg_al==0x12,256,0,reg_bl&0x7f,8);
00235                         break;
00236                 case 0x03:                      /* Set Block Specifier */
00237                         IO_Write(0x3c4,0x3);IO_Write(0x3c5,reg_bl);
00238                         break;
00239                 case 0x04:                      /* Load 8x16 font */
00240                 case 0x14:
00241                         if (!IS_VGA_ARCH) break;
00242                         INT10_LoadFont(Real2Phys(int10.rom.font_16),reg_al==0x14,256,0,reg_bl&0x7f,16);
00243                         break;
00244 /* Graphics mode calls */
00245                 case 0x20:                      /* Set User 8x8 Graphics characters */
00246                         RealSetVec(0x1f,RealMake(SegValue(es),reg_bp));
00247                         break;
00248                 case 0x21:                      /* Set user graphics characters */
00249                         RealSetVec(0x43,RealMake(SegValue(es),reg_bp));
00250                         real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,reg_cx);
00251                         goto graphics_chars;
00252                 case 0x22:                      /* Rom 8x14 set */
00253                         RealSetVec(0x43,int10.rom.font_14);
00254                         real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,14);
00255                         goto graphics_chars;
00256                 case 0x23:                      /* Rom 8x8 double dot set */
00257                         RealSetVec(0x43,int10.rom.font_8_first);
00258                         real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,8);
00259                         goto graphics_chars;
00260                 case 0x24:                      /* Rom 8x16 set */
00261                         if (!IS_VGA_ARCH) break;
00262                         RealSetVec(0x43,int10.rom.font_16);
00263                         real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,16);
00264                         goto graphics_chars;
00265 graphics_chars:
00266                         switch (reg_bl) {
00267                         case 0x00:real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,reg_dl-1);break;
00268                         case 0x01:real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,13);break;
00269                         case 0x03:real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,42);break;
00270                         case 0x02:
00271                         default:real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,24);break;
00272                         }
00273                         break;
00274 /* General */
00275                 case 0x30:/* Get Font Information */
00276                         switch (reg_bh) {
00277                         case 0x00:      /* interupt 0x1f vector */
00278                                 {
00279                                         RealPt int_1f=RealGetVec(0x1f);
00280                                         SegSet16(es,RealSeg(int_1f));
00281                                         reg_bp=RealOff(int_1f);
00282                                 }
00283                                 break;
00284                         case 0x01:      /* interupt 0x43 vector */
00285                                 {
00286                                         RealPt int_43=RealGetVec(0x43);
00287                                         SegSet16(es,RealSeg(int_43));
00288                                         reg_bp=RealOff(int_43);
00289                                 }
00290                                 break;
00291                         case 0x02:      /* font 8x14 */
00292                                 SegSet16(es,RealSeg(int10.rom.font_14));
00293                                 reg_bp=RealOff(int10.rom.font_14);
00294                                 break;
00295                         case 0x03:      /* font 8x8 first 128 */
00296                                 SegSet16(es,RealSeg(int10.rom.font_8_first));
00297                                 reg_bp=RealOff(int10.rom.font_8_first);
00298                                 break;
00299                         case 0x04:      /* font 8x8 second 128 */
00300                                 SegSet16(es,RealSeg(int10.rom.font_8_second));
00301                                 reg_bp=RealOff(int10.rom.font_8_second);
00302                                 break;
00303                         case 0x05:      /* alpha alternate 9x14 */
00304                                 SegSet16(es,RealSeg(int10.rom.font_14_alternate));
00305                                 reg_bp=RealOff(int10.rom.font_14_alternate);
00306                                 break;
00307                         case 0x06:      /* font 8x16 */
00308                                 if (!IS_VGA_ARCH) break;
00309                                 SegSet16(es,RealSeg(int10.rom.font_16));
00310                                 reg_bp=RealOff(int10.rom.font_16);
00311                                 break;
00312                         case 0x07:      /* alpha alternate 9x16 */
00313                                 if (!IS_VGA_ARCH) break;
00314                                 SegSet16(es,RealSeg(int10.rom.font_16_alternate));
00315                                 reg_bp=RealOff(int10.rom.font_16_alternate);
00316                                 break;
00317                         default:
00318                                 LOG(LOG_INT10,LOG_ERROR)("Function 11:30 Request for font %2X",reg_bh); 
00319                                 break;
00320                         }
00321                         if ((reg_bh<=7) || (svgaCard==SVGA_TsengET4K)) {
00322                                 reg_cx=real_readw(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT);
00323                                 reg_dl=real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS);
00324                         }
00325                         break;
00326                 default:
00327                         LOG(LOG_INT10,LOG_ERROR)("Function 11:Unsupported character generator call %2X",reg_al);
00328                         break;
00329                 }
00330                 if ((reg_al&0xf0)==0x10) Mouse_AfterNewVideoMode(false);
00331                 break;
00332         case 0x12:                                                              /* alternate function select */
00333                 if (!IS_EGAVGA_ARCH && machine != MCH_MCGA) 
00334                         break;
00335                 switch (reg_bl) {
00336                 case 0x10:                                                      /* Get EGA Information */
00337             if (machine != MCH_MCGA) {
00338                 /* This call makes no sense on MCGA systems because it's designed to return EGA information.
00339                  *
00340                  * Furthermore the MS-DOS port of Thexder calls this function and validates the values
00341                  * returned from this call in a way that suggests MCGA BIOSes do not respond to this call:
00342                  *
00343                  * 0302:00000377 32C0                xor  al,al
00344                  * 0302:00000379 B310                mov  bl,10
00345                  * 0302:0000037B B7FF                mov  bh,FF
00346                  * 0302:0000037D B10F                mov  cl,0F
00347                  * 0302:0000037F B412                mov  ah,12
00348                  * 0302:00000381 CD10                int  10
00349                  * 0302:00000383 80F90C              cmp  cl,0C
00350                  * 0302:00000386 730D                jnc  00000395 ($+d)         (down)
00351                  * 0302:00000388 80FB03              cmp  bl,03
00352                  * 0302:0000038B 7708                ja   00000395 ($+8)         (no jmp)
00353                  * 0302:0000038D 0AFF                or   bh,bh
00354                  * 0302:0000038F 7504                jne  00000395 ($+4)         (no jmp)
00355                  * 0302:00000391 8D16CD02            lea  dx,[02CD]              ds:[02CD]=616D
00356                  * 0302:00000395 E82C00              call 000003C4 ($+2c)
00357                  *
00358                  * Basically all checks confirm the returned values are out of range and invalid for what
00359                  * the BIOS call would normally return for EGA. Either MCGA BIOS leaves them unchanged
00360                  * or changes them to some other value entirely.
00361                  *
00362                  * [see also: http://www.ctyme.com/intr/rb-0162.htm]
00363                  * [see also: https://github.com/joncampbell123/dosbox-x/issues/1207]
00364                  *
00365                  * TODO: What does actual MCGA hardware/BIOS do? CHECK */
00366                 reg_bh=(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)==0x3B4);
00367                 if (IS_EGA_ARCH) {
00368                     if (vga.mem.memsize >= (256*1024))
00369                         reg_bl=3;       //256 kb
00370                     else if (vga.mem.memsize >= (192*1024))
00371                         reg_bl=2;       //192 kb
00372                     else if (vga.mem.memsize >= (128*1024))
00373                         reg_bl=1;       //128 kb
00374                     else
00375                         reg_bl=0;       //64 kb
00376                 }
00377                 else {
00378                     reg_bl=3;   //256 kb
00379                 }
00380                 reg_cl=real_readb(BIOSMEM_SEG,BIOSMEM_SWITCHES) & 0x0F;
00381                 reg_ch=real_readb(BIOSMEM_SEG,BIOSMEM_SWITCHES) >> 4;
00382             }
00383                         break;
00384                 case 0x20:                                                      /* Set alternate printscreen */
00385                         break;
00386                 case 0x30:                                                      /* Select vertical resolution */
00387                         {   
00388                                 if (!IS_VGA_ARCH) break;
00389                                 LOG(LOG_INT10,LOG_WARN)("Function 12:Call %2X (select vertical resolution)",reg_bl);
00390                                 if (svgaCard != SVGA_None) {
00391                                         if (reg_al > 2) {
00392                                                 reg_al=0;               // invalid subfunction
00393                                                 break;
00394                                         }
00395                                 }
00396                                 Bit8u modeset_ctl = real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
00397                                 Bit8u video_switches = real_readb(BIOSMEM_SEG,BIOSMEM_SWITCHES)&0xf0;
00398                                 switch(reg_al) {
00399                                 case 0: // 200
00400                                         modeset_ctl &= 0xef;
00401                                         modeset_ctl |= 0x80;
00402                                         video_switches |= 8;    // ega normal/cga emulation
00403                                         break;
00404                                 case 1: // 350
00405                                         modeset_ctl &= 0x6f;
00406                                         video_switches |= 9;    // ega enhanced
00407                                         break;
00408                                 case 2: // 400
00409                                         modeset_ctl &= 0x6f;
00410                                         modeset_ctl |= 0x10;    // use 400-line mode at next mode set
00411                                         video_switches |= 9;    // ega enhanced
00412                                         break;
00413                                 default:
00414                                         modeset_ctl &= 0xef;
00415                                         video_switches |= 8;    // ega normal/cga emulation
00416                                         break;
00417                                 }
00418                                 real_writeb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,modeset_ctl);
00419                                 real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,video_switches);
00420                                 reg_al=0x12;    // success
00421                                 break;
00422                         }
00423                 case 0x31:                                                      /* Palette loading on modeset */
00424                         {   
00425                                 if (!IS_VGA_ARCH) break;
00426                                 if (svgaCard==SVGA_TsengET4K) reg_al&=1;
00427                                 if (reg_al>1) {
00428                                         reg_al=0;               //invalid subfunction
00429                                         break;
00430                                 }
00431                                 Bit8u temp = real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL) & 0xf7;
00432                                 if (reg_al&1) temp|=8;          // enable if al=0
00433                                 real_writeb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,temp);
00434                                 reg_al=0x12;
00435                                 break;  
00436                         }               
00437                 case 0x32:                                                      /* Video addressing */
00438                         if (!IS_VGA_ARCH) break;
00439                         LOG(LOG_INT10,LOG_ERROR)("Function 12:Call %2X not handled",reg_bl);
00440                         if (svgaCard==SVGA_TsengET4K) reg_al&=1;
00441                         if (reg_al>1) reg_al=0;         //invalid subfunction
00442                         else reg_al=0x12;                       //fake a success call
00443                         break;
00444                 case 0x33: /* SWITCH GRAY-SCALE SUMMING */
00445                         {   
00446                                 if (!IS_VGA_ARCH) break;
00447                                 if (svgaCard==SVGA_TsengET4K) reg_al&=1;
00448                                 if (reg_al>1) {
00449                                         reg_al=0;
00450                                         break;
00451                                 }
00452                                 Bit8u temp = real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL) & 0xfd;
00453                                 if (!(reg_al&1)) temp|=2;               // enable if al=0
00454                                 real_writeb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,temp);
00455                                 reg_al=0x12;
00456                                 break;  
00457                         }               
00458                 case 0x34: /* ALTERNATE FUNCTION SELECT (VGA) - CURSOR EMULATION */
00459                         {   
00460                                 // bit 0: 0=enable, 1=disable
00461                                 if (!IS_VGA_ARCH) break;
00462                                 if (svgaCard==SVGA_TsengET4K) reg_al&=1;
00463                                 if (reg_al>1) {
00464                                         reg_al=0;
00465                                         break;
00466                                 }
00467                                 Bit8u temp = real_readb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL) & 0xfe;
00468                                 real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,temp|reg_al);
00469                                 reg_al=0x12;
00470                                 break;  
00471                         }               
00472                 case 0x35:
00473                         if (!IS_VGA_ARCH) break;
00474                         LOG(LOG_INT10,LOG_ERROR)("Function 12:Call %2X not handled",reg_bl);
00475                         reg_al=0x12;
00476                         break;
00477                 case 0x36: {                                            /* VGA Refresh control */
00478                         if (!IS_VGA_ARCH) break;
00479                         if ((svgaCard==SVGA_S3Trio) && (reg_al>1)) {
00480                                 reg_al=0;
00481                                 break;
00482                         }
00483                         IO_Write(0x3c4,0x1);
00484                         Bit8u clocking = IO_Read(0x3c5);
00485                         
00486                         if (reg_al==0) clocking &= ~0x20;
00487                         else clocking |= 0x20;
00488                         
00489                         IO_Write(0x3c4,0x1);
00490                         IO_Write(0x3c5,clocking);
00491 
00492                         reg_al=0x12; // success
00493                         break;
00494                 }
00495 #if 0 /* TODO: For Tseng ET4000 emulation. ET4000 W32p driver uses it. */
00496 /*
00497 
00498    INT 10 - Tseng ET-4000 BIOS - GET/SET SCREEN REFRESH RATE
00499 
00500    AH = 12h
00501    BL = F1h
00502    AL = subfunction
00503    00h set refresh rate
00504    01h get refresh rate
00505    BH = video mode
00506    00h   640x480
00507    01h   800x600
00508    02h   1024x768
00509    03h   1280x1024
00510    CX = new refresh rate (see #00035) if AL = 00h
00511 Return: AL = 12h if supported
00512 CX = current rate (for AL=00h, a changed CX indicates failure)
00513 
00514 Values for Tseng ET4000 refresh rate:
00515 CX      640x480 800x600   1024x768/1280x1024
00516 00h     60 Hz    56 Hz     interlaced
00517 01h     72 Hz    60 Hz     60 Hz
00518 02h     75 Hz    72 Hz     70 Hz
00519 03h     90 Hz    75 Hz     75 Hz
00520 04h     --       90 Hz     --
00521 
00522  */
00523 #endif
00524                 default:
00525                         LOG(LOG_INT10,LOG_ERROR)("Function 12:Call %2X not handled",reg_bl);
00526                         if (machine!=MCH_EGA) reg_al=0;
00527                         break;
00528                 }
00529                 break;
00530         case 0x13:                                                              /* Write String */
00531                 INT10_WriteString(reg_dh,reg_dl,reg_al,reg_bl,SegPhys(es)+reg_bp,reg_cx,reg_bh);
00532                 break;
00533         case 0x1A:                                                              /* Display Combination */
00534                 if (!IS_VGA_ARCH && machine != MCH_MCGA) break;
00535                 if (reg_al<2) {
00536                         INT10_DisplayCombinationCode(&reg_bx,(reg_al==1));
00537                         reg_ax=0x1A;    // high part destroyed or zeroed depending on BIOS
00538                 }
00539                 break;
00540         case 0x1B:                                                              /* functionality State Information */
00541                 if (!IS_VGA_ARCH) break;
00542                 switch (reg_bx) {
00543                 case 0x0000:
00544                         INT10_GetFuncStateInformation(SegPhys(es)+reg_di);
00545                         reg_al=0x1B;
00546                         break;
00547                 default:
00548                         LOG(LOG_INT10,LOG_ERROR)("1B:Unhandled call BX %2X",reg_bx);
00549                         reg_al=0;
00550                         break;
00551                 }
00552                 break;
00553         case 0x1C:      /* Video Save Area */
00554                 if (!IS_VGA_ARCH) break;
00555                 switch (reg_al) {
00556                         case 0: {
00557                                 Bitu ret=INT10_VideoState_GetSize(reg_cx);
00558                                 if (ret) {
00559                                         reg_al=0x1c;
00560                                         reg_bx=(Bit16u)ret;
00561                                 } else reg_al=0;
00562                                 }
00563                                 break;
00564                         case 1:
00565                                 if (INT10_VideoState_Save(reg_cx,RealMake(SegValue(es),reg_bx))) reg_al=0x1c;
00566                                 else reg_al=0;
00567                                 break;
00568                         case 2:
00569                                 if (INT10_VideoState_Restore(reg_cx,RealMake(SegValue(es),reg_bx))) reg_al=0x1c;
00570                                 else reg_al=0;
00571                                 break;
00572                         default:
00573                                 if (svgaCard==SVGA_TsengET4K) reg_ax=0;
00574                                 else reg_al=0;
00575                                 break;
00576                 }
00577                 break;
00578         case 0x4f:                                                              /* VESA Calls */
00579                 if ((!IS_VGA_ARCH) || (svgaCard!=SVGA_S3Trio))
00580                         break;
00581                 switch (reg_al) {
00582                 case 0x00:                                                      /* Get SVGA Information */
00583                         reg_al=0x4f;
00584                         reg_ah=VESA_GetSVGAInformation(SegValue(es),reg_di);
00585                         break;
00586                 case 0x01:                                                      /* Get SVGA Mode Information */
00587                         reg_al=0x4f;
00588                         reg_ah=VESA_GetSVGAModeInformation(reg_cx,SegValue(es),reg_di);
00589                         break;
00590                 case 0x02:                                                      /* Set videomode */
00591                         Mouse_BeforeNewVideoMode(true);
00592                         reg_al=0x4f;
00593                         reg_ah=VESA_SetSVGAMode(reg_bx);
00594                         Mouse_AfterNewVideoMode(true);
00595                         break;
00596                 case 0x03:                                                      /* Get videomode */
00597                         reg_al=0x4f;
00598                         reg_ah=VESA_GetSVGAMode(reg_bx);
00599                         break;
00600                 case 0x04:                                                      /* Save/restore state */
00601                         reg_al=0x4f;
00602                         switch (reg_dl) {
00603                                 case 0: {
00604                                         Bitu ret=INT10_VideoState_GetSize(reg_cx);
00605                                         if (ret) {
00606                                                 reg_ah=0;
00607                                                 reg_bx=(Bit16u)ret;
00608                                         } else reg_ah=1;
00609                                         }
00610                                         break;
00611                                 case 1:
00612                                         if (INT10_VideoState_Save(reg_cx,RealMake(SegValue(es),reg_bx))) reg_ah=0;
00613                                         else reg_ah=1;
00614                                         break;
00615                                 case 2:
00616                                         if (INT10_VideoState_Restore(reg_cx,RealMake(SegValue(es),reg_bx))) reg_ah=0;
00617                                         else reg_ah=1;
00618                                         break;
00619                                 default:
00620                                         reg_ah=1;
00621                                         break;
00622                         }
00623                         break;
00624                 case 0x05:                                                      
00625                         if (reg_bh==0) {                                /* Set CPU Window */
00626                                 reg_ah=VESA_SetCPUWindow(reg_bl,reg_dl);
00627                                 reg_al=0x4f;
00628                         } else if (reg_bh == 1) {               /* Get CPU Window */
00629                                 reg_ah=VESA_GetCPUWindow(reg_bl,reg_dx);
00630                                 reg_al=0x4f;
00631                         } else {
00632                                 LOG(LOG_INT10,LOG_ERROR)("Unhandled VESA Function %X Subfunction %X",reg_al,reg_bh);
00633                                 reg_ah=0x01;
00634                         }
00635                         break;
00636                 case 0x06:
00637                         reg_al=0x4f;
00638                         reg_ah=VESA_ScanLineLength(reg_bl,reg_cx,reg_bx,reg_cx,reg_dx);
00639                         break;
00640                 case 0x07:
00641                         switch (reg_bl) {
00642                         case 0x80:                                              /* Set Display Start during retrace */
00643                         case 0x00:                                              /* Set display Start */
00644                                 reg_al=0x4f;
00645                                 reg_ah=VESA_SetDisplayStart(reg_cx,reg_dx,reg_bl==0x80);
00646                                 break;
00647                         case 0x01:
00648                                 reg_al=0x4f;
00649                                 reg_bh=0x00;                            //reserved
00650                                 reg_ah=VESA_GetDisplayStart(reg_cx,reg_dx);
00651                                 break;
00652                         default:
00653                                 LOG(LOG_INT10,LOG_ERROR)("Unhandled VESA Function %X Subfunction %X",reg_al,reg_bl);
00654                                 reg_ah=0x1;
00655                                 break;
00656                         }
00657                         break;
00658         case 0x08:
00659             switch (reg_bl) {
00660                 case 0x00:                  /* Set DAC width */
00661                     if (CurMode->type == M_LIN8) {
00662                         /* TODO: If there is a bit on S3 cards to control DAC width in "pseudocolor" modes, replace this code
00663                          *       with something to write that bit instead of internal state change like this. */
00664                         if (reg_bh >= 8 && enable_vga_8bit_dac)
00665                             vga_8bit_dac = true;
00666                         else
00667                             vga_8bit_dac = false;
00668 
00669                         VGA_DAC_UpdateColorPalette();
00670                         reg_bh=(vga_8bit_dac ? 8 : 6);
00671                         reg_al=0x4f;
00672                         reg_ah=0x0;
00673 
00674                         LOG(LOG_INT10,LOG_NORMAL)("VESA BIOS called to set VGA DAC width to %u bits",reg_bh);
00675                     }
00676                     else {
00677                         reg_al=0x4f;
00678                         reg_ah=0x3;
00679                     }
00680                     break;
00681                 case 0x01:                  /* Get DAC width */
00682                     if (CurMode->type == M_LIN8) {
00683                         reg_bh=(vga_8bit_dac ? 8 : 6);
00684                         reg_al=0x4f;
00685                         reg_ah=0x0;
00686                     }
00687                     else {
00688                         reg_al=0x4f;
00689                         reg_ah=0x3;
00690                     }
00691                     break;
00692                 default:
00693                     LOG(LOG_INT10,LOG_ERROR)("Unhandled VESA Function %X Subfunction %X",reg_al,reg_bl);
00694                     reg_ah=0x1;
00695                     break;
00696             }
00697             break;
00698                 case 0x09:
00699                         switch (reg_bl) {
00700                         case 0x80:                                              /* Set Palette during retrace */
00701                         case 0x00:                                              /* Set Palette */
00702                                 reg_ah=VESA_SetPalette(SegPhys(es)+reg_di,reg_dx,reg_cx,reg_bl==0x80);
00703                                 reg_al=0x4f;
00704                                 break;
00705                         case 0x01:                                              /* Get Palette */
00706                                 reg_ah=VESA_GetPalette(SegPhys(es)+reg_di,reg_dx,reg_cx);
00707                                 reg_al=0x4f;
00708                                 break;
00709                         default:
00710                                 LOG(LOG_INT10,LOG_ERROR)("Unhandled VESA Function %X Subfunction %X",reg_al,reg_bl);
00711                                 reg_ah=0x01;
00712                                 break;
00713                         }
00714                         break;
00715                 case 0x0a:                                                      /* Get Pmode Interface */
00716                         if (int10.vesa_oldvbe) {
00717                                 reg_ax=0x014f;
00718                                 break;
00719                         }
00720                         switch (reg_bl) {
00721                         case 0x00:
00722                                 SegSet16(es,RealSeg(int10.rom.pmode_interface));
00723                                 reg_di=RealOff(int10.rom.pmode_interface);
00724                                 reg_cx=int10.rom.pmode_interface_size;
00725                                 reg_ax=0x004f;
00726                                 break;
00727                         case 0x01:                                              /* Get code for "set window" */
00728                                 SegSet16(es,RealSeg(int10.rom.pmode_interface));
00729                                 reg_di=RealOff(int10.rom.pmode_interface)+(Bit32u)int10.rom.pmode_interface_window;
00730                                 reg_cx=int10.rom.pmode_interface_start-int10.rom.pmode_interface_window;
00731                                 reg_ax=0x004f;
00732                                 break;
00733                         case 0x02:                                              /* Get code for "set display start" */
00734                                 SegSet16(es,RealSeg(int10.rom.pmode_interface));
00735                                 reg_di=RealOff(int10.rom.pmode_interface)+(Bit32u)int10.rom.pmode_interface_start;
00736                                 reg_cx=int10.rom.pmode_interface_palette-int10.rom.pmode_interface_start;
00737                                 reg_ax=0x004f;
00738                                 break;
00739                         case 0x03:                                              /* Get code for "set palette" */
00740                                 SegSet16(es,RealSeg(int10.rom.pmode_interface));
00741                                 reg_di=RealOff(int10.rom.pmode_interface)+(Bit32u)int10.rom.pmode_interface_palette;
00742                                 reg_cx=int10.rom.pmode_interface_size-int10.rom.pmode_interface_palette;
00743                                 reg_ax=0x004f;
00744                                 break;
00745                         default:
00746                                 reg_ax=0x014f;
00747                                 break;
00748                         }
00749                         break;
00750 
00751                 default:
00752                         LOG(LOG_INT10,LOG_ERROR)("Unhandled VESA Function %X",reg_al);
00753                         reg_al=0x0;
00754                         break;
00755                 }
00756                 break;
00757         case 0xf0:
00758                 INT10_EGA_RIL_ReadRegister(reg_bl, reg_dx);
00759                 break;
00760         case 0xf1:
00761                 INT10_EGA_RIL_WriteRegister(reg_bl, reg_bh, reg_dx);
00762                 break;
00763         case 0xf2:
00764                 INT10_EGA_RIL_ReadRegisterRange(reg_ch, reg_cl, reg_dx, SegPhys(es)+reg_bx);
00765                 break;
00766         case 0xf3:
00767                 INT10_EGA_RIL_WriteRegisterRange(reg_ch, reg_cl, reg_dx, SegPhys(es)+reg_bx);
00768                 break;
00769         case 0xf4:
00770                 INT10_EGA_RIL_ReadRegisterSet(reg_cx, SegPhys(es)+reg_bx);
00771                 break;
00772         case 0xf5:
00773                 INT10_EGA_RIL_WriteRegisterSet(reg_cx, SegPhys(es)+reg_bx);
00774                 break;
00775         case 0xfa: {
00776                 RealPt pt=INT10_EGA_RIL_GetVersionPt();
00777                 SegSet16(es,RealSeg(pt));
00778                 reg_bx=RealOff(pt);
00779                 }
00780                 break;
00781         case 0xff:
00782                 if (!warned_ff) LOG(LOG_INT10,LOG_NORMAL)("INT10:FF:Weird NC call");
00783                 warned_ff=true;
00784                 break;
00785         default:
00786                 LOG(LOG_INT10,LOG_ERROR)("Function %4X not supported",reg_ax);
00787 //              reg_al=0x00;            //Successfull, breaks marriage
00788                 break;
00789         }
00790         return CBRET_NONE;
00791 }
00792 
00793 static void INT10_Seg40Init(void) {
00794         // the default char height
00795         real_writeb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,16);
00796         // Clear the screen 
00797         real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,0x60);
00798         // Set the basic screen we have
00799         real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
00800         // Set the basic modeset options
00801         real_writeb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,0x51); // why is display switching enabled (bit 6) ?
00802         // Set the  default MSR
00803         real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x09);
00804         // Set the pointer to video save pointer table
00805         real_writed(BIOSMEM_SEG, BIOSMEM_VS_POINTER, int10.rom.video_save_pointers);
00806 }
00807 
00808 static void INT10_InitVGA(void) {
00809         if (IS_EGAVGA_ARCH) {
00810                 LOG(LOG_MISC,LOG_DEBUG)("INT 10: initializing EGA/VGA state");
00811 
00812                 /* switch to color mode and enable CPU access 480 lines */
00813                 IO_Write(0x3c2,0xc3);
00814                 /* More than 64k */
00815                 IO_Write(0x3c4,0x04);
00816                 IO_Write(0x3c5,0x02);
00817                 if (IS_VGA_ARCH) {
00818                         /* Initialize DAC */
00819                         IO_Write(0x3c8,0);
00820                         for (Bitu i=0;i<3*256;i++) IO_Write(0x3c9,0);
00821                 }
00822         }
00823 }
00824 
00825 static void SetupTandyBios(void) {
00826         if (machine==MCH_TANDY) {
00827                 unsigned int i;
00828                 static Bit8u TandyConfig[130]= {
00829                 0x21, 0x42, 0x49, 0x4f, 0x53, 0x20, 0x52, 0x4f, 0x4d, 0x20, 0x76, 0x65, 0x72,
00830                 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x30, 0x32, 0x2e, 0x30, 0x30, 0x2e, 0x30, 0x30,
00831                 0x0d, 0x0a, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x69,
00832                 0x74, 0x79, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0d, 0x0a,
00833                 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29,
00834                 0x20, 0x31, 0x39, 0x38, 0x34, 0x2c, 0x31, 0x39, 0x38, 0x35, 0x2c, 0x31, 0x39,
00835                 0x38, 0x36, 0x2c, 0x31, 0x39, 0x38, 0x37, 0x0d, 0x0a, 0x50, 0x68, 0x6f, 0x65,
00836                 0x6e, 0x69, 0x78, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20,
00837                 0x41, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x73, 0x20, 0x4c, 0x74,
00838                 0x64, 0x2e, 0x0d, 0x0a, 0x61, 0x6e, 0x64, 0x20, 0x54, 0x61, 0x6e, 0x64, 0x79
00839                 };
00840 
00841                 LOG(LOG_MISC,LOG_DEBUG)("Initializing Tandy video state (video BIOS init)");
00842 
00843                 for(i=0;i<130;i++)
00844                         phys_writeb(0xf0000+i+0xc000, TandyConfig[i]);
00845         }
00846 }
00847 
00848 bool MEM_map_ROM_physmem(Bitu start,Bitu end);
00849 
00850 extern Bitu VGA_BIOS_Size;
00851 extern Bitu VGA_BIOS_SEG;
00852 extern Bitu VGA_BIOS_SEG_END;
00853 extern bool VIDEO_BIOS_disable;
00854 extern Bitu BIOS_VIDEO_TABLE_LOCATION;
00855 extern Bitu BIOS_VIDEO_TABLE_SIZE;
00856 
00857 bool ROMBIOS_FreeMemory(Bitu phys);
00858 Bitu RealToPhys(Bitu x);
00859 
00860 void BIOS_UnsetupDisks(void);
00861 void BIOS_UnsetupKeyboard(void);
00862 bool MEM_unmap_physmem(Bitu start,Bitu end);
00863 void CALLBACK_DeAllocate(Bitu in);
00864 
00865 void INT10_OnResetComplete() {
00866     if (VGA_BIOS_Size > 0)
00867         MEM_unmap_physmem(0xC0000,0xC0000+VGA_BIOS_Size-1);
00868 
00869     /* free the table */
00870     BIOS_VIDEO_TABLE_SIZE = 0;
00871     if (BIOS_VIDEO_TABLE_LOCATION != (~0U) && BIOS_VIDEO_TABLE_LOCATION != 0) {
00872         LOG(LOG_MISC,LOG_DEBUG)("INT 10h freeing BIOS VIDEO TABLE LOCATION");
00873         ROMBIOS_FreeMemory(RealToPhys(BIOS_VIDEO_TABLE_LOCATION));
00874         BIOS_VIDEO_TABLE_LOCATION = ~0u;                // RealMake(0xf000,0xf0a4)
00875     }
00876 
00877     void VESA_OnReset_Clear_Callbacks(void);
00878     VESA_OnReset_Clear_Callbacks();
00879 
00880     if (call_10 != 0) {
00881         CALLBACK_DeAllocate(call_10);
00882         call_10 = 0;
00883     }
00884 
00885     BIOS_UnsetupDisks();
00886     BIOS_UnsetupKeyboard();
00887 }
00888 
00889 extern bool vesa_zero_on_get_information;
00890 extern bool unmask_irq0_on_int10_setmode;
00891 extern bool int16_unmask_irq1_on_read;
00892 extern bool int10_vga_bios_vector;
00893 extern bool int16_ah_01_cf_undoc;
00894 
00895 #if 0 /* reference */
00896 typedef struct tagBITMAPFILEHEADER {
00897     WORD  bfType;
00898     DWORD bfSize;
00899     WORD  bfReserved1;
00900     WORD  bfReserved2;
00901     DWORD bfOffBits;
00902 } BITMAPFILEHEADER, *PBITMAPFILEHEADER;
00903 
00904 typedef struct tagBITMAPINFO {
00905     BITMAPINFOHEADER bmiHeader;
00906     RGBQUAD          bmiColors[1];
00907 } BITMAPINFO, *PBITMAPINFO;
00908 
00909 typedef struct tagBITMAPINFOHEADER {
00910     DWORD biSize;
00911     LONG  biWidth;
00912     LONG  biHeight;
00913     WORD  biPlanes;
00914     WORD  biBitCount;
00915     DWORD biCompression;
00916     DWORD biSizeImage;
00917     LONG  biXPelsPerMeter;
00918     LONG  biYPelsPerMeter;
00919     DWORD biClrUsed;
00920     DWORD biClrImportant;
00921 } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
00922 #endif
00923 
00924 bool Load_FONT_ROM(void) {
00925     unsigned int hibyte,lowbyte,r;
00926     unsigned char tmp[256*16]; // 8x16 256 cells
00927     FILE *fp;
00928 
00929              fp = fopen("font.rom","rb");
00930     if (!fp) fp = fopen("FONT.rom","rb");
00931     if (!fp) fp = fopen("font.ROM","rb");
00932     if (!fp) fp = fopen("FONT.ROM","rb");
00933     if (!fp) {
00934         LOG_MSG("PC-98 font loading: FONT.ROM not found");
00935         return false;
00936     }
00937 
00938     // prepare
00939     memset(vga.draw.font,0,sizeof(vga.draw.font));
00940 
00941     /* FONT.ROM is always 288768 bytes large and contains:
00942      *
00943      * 256      8x8     Single-wide character cells         at      0x00000
00944      * 256      8x16    Single-wide character cells         at      0x00800
00945      * 96 x 92  16x16   Double-wide character cells         at      0x01800 */
00946     fseek(fp,0,SEEK_END);
00947     if (ftell(fp) != 288768) {
00948         LOG_MSG("PC-98 FONT.ROM is not the correct size");
00949         goto fail;
00950     }
00951     fseek(fp,0,SEEK_SET);
00952 
00953     /* NTS: We do not yet use the 8x8 character set */
00954 
00955     /* 8x16 single-wide */
00956     fseek(fp,0x800,SEEK_SET);
00957     if (fread(tmp,256*16,1,fp) != 1) goto fail;
00958     for (lowbyte=0;lowbyte < 256;lowbyte++) {
00959         for (r=0;r < 16;r++) {
00960             vga.draw.font[(lowbyte*16)+r] = tmp[(lowbyte*16)+r];
00961         }
00962     }
00963 
00964     /* 16x16 double-wide */
00965     assert(sizeof(tmp) >= (96 * 16 * 2));
00966     for (lowbyte=0x01;lowbyte < 0x5D;lowbyte++) {
00967         fseek(fp,long(0x1800u + ((lowbyte - 0x01u) * 96u * 16u * 2u/*16 wide*/)),SEEK_SET);
00968         if (fread(tmp,96 * 16 * 2/*16 wide*/,1,fp) != 1) goto fail;
00969 
00970         for (hibyte=0;hibyte < 96;hibyte++) {
00971             unsigned int i;
00972             unsigned int o;
00973 
00974             i = hibyte * 16 * 2;
00975             o = (((hibyte + 0x20) * 128) + lowbyte) * 16 * 2;
00976 
00977             for (r=0;r < 16;r++) {
00978                 vga.draw.font[o+(r*2)  ] = tmp[i+r+0];
00979                 vga.draw.font[o+(r*2)+1] = tmp[i+r+16];
00980             }
00981         }
00982     }
00983 
00984     LOG_MSG("FONT.ROM loaded");
00985     fclose(fp);
00986     return true;
00987 fail:
00988     fclose(fp);
00989     return false;
00990 }
00991 
00992 /* ANEX86.BMP from the Anex86 emulator.
00993  * Holds the font as a giant 2048x2048 1-bit monochromatic bitmap. */
00994 /* We load it separately because I am uncertain whether it is legal or not to
00995  * incorporate this directly into DOSBox-X. */
00996 bool Load_Anex86_Font(void) {
00997     unsigned char tmp[(2048/8)*16]; /* enough for one 2048x16 row and bitmap header */
00998     unsigned int hibyte,lowbyte,r;
00999     unsigned int bmp_ofs;
01000     FILE *fp = NULL;
01001 
01002     /* ANEX86.BMP accurate dump of actual font */
01003     fp = fopen("anex86.bmp","rb");
01004     if (!fp) fp = fopen("ANEX86.bmp","rb");
01005     if (!fp) fp = fopen("ANEX86.BMP","rb");
01006 
01007     /* FREECG98.BMP free open source generated copy from system fonts */
01008     if (!fp) fp = fopen("freecg98.bmp","rb");
01009     if (!fp) fp = fopen("FREECG98.bmp","rb");
01010     if (!fp) fp = fopen("FREECG98.BMP","rb");
01011 
01012     /* Linux builds allow FREECG98.BMP in /usr/share/dosbox-x */
01013     /* Mac OS X builds carry FREECG98.BMP in the Resources subdirectory of the .app bundle */
01014     {
01015         std::string resdir,tmpdir;
01016 
01017         Cross::GetPlatformResDir(resdir);
01018         if (!resdir.empty()) {
01019             /* FREECG98.BMP free open source generated copy from system fonts */
01020             if (!fp) {
01021                 tmpdir = resdir + "freecg98.bmp";
01022                 fp = fopen(tmpdir.c_str(),"rb");
01023             }
01024             if (!fp) {
01025                 tmpdir = resdir + "FREECG98.BMP";
01026                 fp = fopen(tmpdir.c_str(),"rb");
01027             }
01028         }
01029     }
01030 
01031     if (!fp) {
01032         LOG_MSG("PC-98 font loading: neither ANEX86.BMP nor FREECG98.BMP found");
01033         return false;
01034     }
01035 
01036     if (fread(tmp,14,1,fp) != 1) goto fail; // BITMAPFILEHEADER
01037     if (memcmp(tmp,"BM",2) != 0) goto fail; // must be "BM"
01038     bmp_ofs = host_readd((HostPt)(tmp+10)); // bOffBits
01039 
01040     if (fread(tmp,40,1,fp) != 1) goto fail; // BITMAPINFOHEADER
01041     if (host_readd((HostPt)(tmp+0)) != 40) goto fail; // biSize == 40 or else
01042     if (host_readd((HostPt)(tmp+4)) != 2048) goto fail; // biWidth == 2048 or else
01043     if (host_readd((HostPt)(tmp+8)) != 2048) goto fail; // biHeight == 2048 or else
01044     if (host_readw((HostPt)(tmp+12)) != 1) goto fail; // biPlanes == 1 or else
01045     if (host_readw((HostPt)(tmp+14)) != 1) goto fail; // biBitCount == 1 or else
01046     if (host_readd((HostPt)(tmp+16)) != 0) goto fail; // biCompression == 0 or else
01047 
01048     /* first row is 8x16 single width */
01049     fseek(fp,long(bmp_ofs+((2048u-16u)*(2048u/8u))),SEEK_SET); /* arrrgh bitmaps are upside-down */
01050     if (fread(tmp,(2048/8)*16,1,fp) != 1) goto fail;
01051     for (lowbyte=0;lowbyte < 256;lowbyte++) {
01052         for (r=0;r < 16;r++) {
01053             vga.draw.font[(lowbyte*16)+r] = tmp[lowbyte+((15-r/*upside-down!*/)*(2048/8))] ^ 0xFF/*ANEX86 has inverse color scheme*/;
01054         }
01055     }
01056     /* everything after is 16x16 fullwidth.
01057      * note: 2048 / 16 = 128 */
01058     for (hibyte=1;hibyte < 128;hibyte++) {
01059         fseek(fp,long(bmp_ofs+((2048u-(16u*hibyte)-16u)*(2048u/8u))),SEEK_SET); /* arrrgh bitmaps are upside-down */
01060         if (fread(tmp,(2048/8)*16,1,fp) != 1) goto fail;
01061 
01062         for (lowbyte=0;lowbyte < 128;lowbyte++) {
01063             for (r=0;r < 16;r++) {
01064                 unsigned int i;
01065                 unsigned int o;
01066 
01067                 /* NTS: fullwidth is 16x16 128 chars across.
01068                  * each row of the char bitmap is TWO bytes. */
01069                 i = (lowbyte*2)+((15-r/*upside-down!*/)*(2048/8));
01070                 o = ((((hibyte*128)+lowbyte)*16)+r)*2;
01071 
01072                 assert((i+2) <= sizeof(tmp));
01073                 assert((o+2) <= sizeof(vga.draw.font));
01074 
01075                 vga.draw.font[o+0] = tmp[i+0] ^ 0xFF;
01076                 vga.draw.font[o+1] = tmp[i+1] ^ 0xFF;
01077             }
01078         }
01079     }
01080 
01081     LOG_MSG("ANEX86.BMP/FREECG98.BMP font loaded");
01082     fclose(fp);
01083     return true;
01084 fail:
01085     LOG_MSG("ANEX86.BMP/FREECG98.BMP invalid, ignoring");
01086     fclose(fp);
01087     return false;
01088 }
01089 
01090 extern Bit8u int10_font_16[256 * 16];
01091 
01092 extern VideoModeBlock PC98_Mode;
01093 
01094 bool Load_VGAFont_As_PC98(void) {
01095     unsigned int i;
01096 
01097     for (i=0;i < (256 * 16);i++)
01098         vga.draw.font[i] = int10_font_16[i];
01099 
01100     return true;
01101 }
01102 
01103 void INT10_EnterPC98(Section *sec) {
01104     (void)sec;//UNUSED
01105     /* deprecated */
01106 }
01107 
01108 RealPt GetSystemBiosINT10Vector(void) {
01109     if (call_10 != 0)
01110         return CALLBACK_RealPointer(call_10);
01111     else
01112         return 0;
01113 }
01114 
01115 void INT10_Startup(Section *sec) {
01116     (void)sec;//UNUSED
01117         LOG(LOG_MISC,LOG_DEBUG)("INT 10h reinitializing");
01118 
01119     vesa_zero_on_get_information = static_cast<Section_prop *>(control->GetSection("dosbox"))->Get_bool("vesa zero buffer on get information");
01120     unmask_irq0_on_int10_setmode = static_cast<Section_prop *>(control->GetSection("dosbox"))->Get_bool("unmask timer on int 10 setmode");
01121         int16_unmask_irq1_on_read = static_cast<Section_prop *>(control->GetSection("dosbox"))->Get_bool("unmask keyboard on int 16 read");
01122     int16_ah_01_cf_undoc = static_cast<Section_prop *>(control->GetSection("dosbox"))->Get_bool("int16 keyboard polling undocumented cf behavior");
01123     int10_vga_bios_vector = static_cast<Section_prop *>(control->GetSection("dosbox"))->Get_bool("int 10h points at vga bios");
01124 
01125     if (!IS_PC98_ARCH) {
01126         INT10_InitVGA();
01127         if (IS_TANDY_ARCH) SetupTandyBios();
01128         /* Setup the INT 10 vector */
01129         call_10=CALLBACK_Allocate();    
01130         CALLBACK_Setup(call_10,&INT10_Handler,CB_IRET,"Int 10 video");
01131         RealSetVec(0x10,CALLBACK_RealPointer(call_10));
01132         //Init the 0x40 segment and init the datastructures in the the video rom area
01133         INT10_SetupRomMemory();
01134         INT10_Seg40Init();
01135         INT10_SetupBasicVideoParameterTable();
01136 
01137         LOG(LOG_MISC,LOG_DEBUG)("INT 10: VGA bios used %d / %d memory",(int)int10.rom.used,(int)VGA_BIOS_Size);
01138         if (int10.rom.used > VGA_BIOS_Size) /* <- this is fatal, it means the Setup() functions scrozzled over the adjacent ROM or RAM area */
01139             E_Exit("VGA BIOS size too small %u > %u",(unsigned int)int10.rom.used,(unsigned int)VGA_BIOS_Size);
01140 
01141         /* NTS: Uh, this does seem bass-ackwards... INT 10h making the VGA BIOS appear. Can we refactor this a bit? */
01142         if (VGA_BIOS_Size > 0) {
01143             LOG(LOG_MISC,LOG_DEBUG)("VGA BIOS occupies segment 0x%04x-0x%04x",(int)VGA_BIOS_SEG,(int)VGA_BIOS_SEG_END-1);
01144             if (!MEM_map_ROM_physmem(0xC0000,0xC0000+VGA_BIOS_Size-1))
01145                 LOG(LOG_MISC,LOG_WARN)("INT 10 video: unable to map BIOS");
01146         }
01147         else {
01148             LOG(LOG_MISC,LOG_DEBUG)("Not mapping VGA BIOS");
01149         }
01150 
01151         INT10_SetVideoMode(0x3);
01152     }
01153     else {
01154         /* load PC-98 character ROM data, if possible */
01155         {
01156             /* We can use FONT.ROM as generated by T98Tools */
01157             bool ok = Load_FONT_ROM();
01158             /* We can use ANEX86.BMP from the Anex86 emulator */
01159             if (!ok) ok = Load_Anex86_Font();
01160             /* Failing all else we can just re-use the IBM VGA 8x16 font to show SOMETHING on the screen.
01161              * Japanese text will not display properly though. */
01162             if (!ok) ok = Load_VGAFont_As_PC98();
01163         }
01164 
01165         CurMode = &PC98_Mode;
01166 
01167         /* FIXME: This belongs in MS-DOS kernel init, because these reside in the CON driver */
01168         /* Some PC-98 game behavior seems to suggest the BIOS data area stretches all the way from segment 0x40:0x00 to segment 0x7F:0x0F inclusive.
01169          * Compare that to IBM PC platform, where segment fills only 0x40:0x00 to 0x50:0x00 inclusive and extra state is held in the "Extended BIOS Data Area".
01170          */
01171 
01172         /* number of text rows on the screen.
01173          * Touhou Project will not clear/format the text layer properly without this variable. */
01174         mem_writeb(0x710,0); /* cursor position Y coordinate */
01175         mem_writeb(0x711,1); /* function definition display status flag */
01176         mem_writeb(0x712,25 - 1 - 1); /* scroll range lower limit (usually 23 when function key row is visible) */
01177         mem_writeb(0x713,1); /* normal 25 lines */
01178         mem_writeb(0x714,0xE1); /* content erase attribute */
01179 
01180         mem_writeb(0x719,0x20); /* content erase character */
01181 
01182         mem_writeb(0x71B,0x01); /* cursor displayed */
01183         mem_writeb(0x71C,0x00); /* cursor position X coordinate */
01184         mem_writeb(0x71D,0xE1); /* content display attribute */
01185         mem_writeb(0x71E,0x00); /* scroll range upper limit (usually 0) */
01186         mem_writeb(0x71F,0x01); /* scrolling speed is normal */
01187 
01188         /* init text RAM */
01189         for (unsigned int i=0;i < 0x1FE0;i += 2) {
01190             mem_writew(0xA0000+i,0);
01191             mem_writeb(0xA2000+i,0xE1);
01192         }
01193         /* clear graphics RAM */
01194         for (unsigned int i=0;i < 0x8000;i += 2) {
01195             mem_writew(0xA8000+i,0);
01196             mem_writew(0xB0000+i,0);
01197             mem_writew(0xB8000+i,0);
01198             mem_writew(0xE0000+i,0);
01199         }
01200     }
01201 }
01202 
01203 void INT10_Init() {
01204 }
01205 
01206 //save state support
01207 namespace
01208 {
01209 class SerializeInt10 : public SerializeGlobalPOD
01210 {
01211 public:
01212     SerializeInt10() : SerializeGlobalPOD("Int10")
01213     {
01214         registerPOD(int10);
01215         //registerPOD(CurMode);
01216         //registerPOD(call_10);
01217         //registerPOD(warned_ff);
01218     }
01219 
01220          //   virtual void setBytes(std::istream& stream)
01221     //{
01222       //  SerializeGlobalPOD::setBytes(stream);
01223                 //}
01224 } dummy;
01225 }