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