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