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