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