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 /* Character displaying moving functions */ 00021 00022 #include "dosbox.h" 00023 #include "bios.h" 00024 #include "mem.h" 00025 #include "inout.h" 00026 #include "int10.h" 00027 #include "shiftjis.h" 00028 #include "callback.h" 00029 00030 Bit8u DefaultANSIAttr(); 00031 00032 #if defined(_MSC_VER) 00033 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */ 00034 #endif 00035 00036 static void MCGA2_CopyRow(Bit8u cleft,Bit8u cright,Bit8u rold,Bit8u rnew,PhysPt base) { 00037 Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00038 PhysPt dest=base+((CurMode->twidth*rnew)*cheight+cleft); 00039 PhysPt src=base+((CurMode->twidth*rold)*cheight+cleft); 00040 Bitu copy=(Bitu)(cright-cleft); 00041 Bitu nextline=CurMode->twidth; 00042 for (Bitu i=0;i<cheight;i++) { 00043 MEM_BlockCopy(dest,src,copy); 00044 dest+=nextline;src+=nextline; 00045 } 00046 } 00047 00048 static void CGA2_CopyRow(Bit8u cleft,Bit8u cright,Bit8u rold,Bit8u rnew,PhysPt base) { 00049 Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00050 PhysPt dest=base+((CurMode->twidth*rnew)*(cheight/2)+cleft); 00051 PhysPt src=base+((CurMode->twidth*rold)*(cheight/2)+cleft); 00052 Bitu copy=(Bitu)(cright-cleft); 00053 Bitu nextline=CurMode->twidth; 00054 for (Bitu i=0;i<cheight/2U;i++) { 00055 MEM_BlockCopy(dest,src,copy); 00056 MEM_BlockCopy(dest+8*1024,src+8*1024,copy); 00057 dest+=nextline;src+=nextline; 00058 } 00059 } 00060 00061 static void CGA4_CopyRow(Bit8u cleft,Bit8u cright,Bit8u rold,Bit8u rnew,PhysPt base) { 00062 Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00063 PhysPt dest=base+((CurMode->twidth*rnew)*(cheight/2)+cleft)*2; 00064 PhysPt src=base+((CurMode->twidth*rold)*(cheight/2)+cleft)*2; 00065 Bitu copy=(Bitu)(cright-cleft)*2u;Bitu nextline=(Bitu)CurMode->twidth*2u; 00066 for (Bitu i=0;i<cheight/2U;i++) { 00067 MEM_BlockCopy(dest,src,copy); 00068 MEM_BlockCopy(dest+8*1024,src+8*1024,copy); 00069 dest+=nextline;src+=nextline; 00070 } 00071 } 00072 00073 static void TANDY16_CopyRow(Bit8u cleft,Bit8u cright,Bit8u rold,Bit8u rnew,PhysPt base) { 00074 Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00075 Bit8u banks=CurMode->twidth/10; 00076 PhysPt dest=base+((CurMode->twidth*rnew)*(cheight/banks)+cleft)*4; 00077 PhysPt src=base+((CurMode->twidth*rold)*(cheight/banks)+cleft)*4; 00078 Bitu copy=(Bitu)(cright-cleft)*4u;Bitu nextline=(Bitu)CurMode->twidth*4u; 00079 for (Bitu i=0;i<static_cast<Bitu>(cheight/banks);i++) { 00080 for (Bitu b=0;b<banks;b++) MEM_BlockCopy(dest+b*8*1024,src+b*8*1024,copy); 00081 dest+=nextline;src+=nextline; 00082 } 00083 } 00084 00085 static void EGA16_CopyRow(Bit8u cleft,Bit8u cright,Bit8u rold,Bit8u rnew,PhysPt base) { 00086 PhysPt src,dest;Bitu copy; 00087 Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00088 dest=base+(CurMode->twidth*rnew)*cheight+cleft; 00089 src=base+(CurMode->twidth*rold)*cheight+cleft; 00090 Bitu nextline=(Bitu)CurMode->twidth; 00091 /* Setup registers correctly */ 00092 IO_Write(0x3ce,5);IO_Write(0x3cf,1); /* Memory transfer mode */ 00093 IO_Write(0x3c4,2);IO_Write(0x3c5,0xf); /* Enable all Write planes */ 00094 /* Do some copying */ 00095 Bitu rowsize=(Bitu)(cright-cleft); 00096 copy=cheight; 00097 for (;copy>0;copy--) { 00098 for (Bitu x=0;x<rowsize;x++) mem_writeb(dest+x,mem_readb(src+x)); 00099 dest+=nextline;src+=nextline; 00100 } 00101 /* Restore registers */ 00102 IO_Write(0x3ce,5);IO_Write(0x3cf,0); /* Normal transfer mode */ 00103 } 00104 00105 static void VGA_CopyRow(Bit8u cleft,Bit8u cright,Bit8u rold,Bit8u rnew,PhysPt base) { 00106 PhysPt src,dest;Bitu copy; 00107 Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00108 dest=base+8u*((CurMode->twidth*rnew)*cheight+cleft); 00109 src=base+8u*((CurMode->twidth*rold)*cheight+cleft); 00110 Bitu nextline=8u*(Bitu)CurMode->twidth; 00111 Bitu rowsize=8u*(Bitu)(cright-cleft); 00112 copy=cheight; 00113 for (;copy>0;copy--) { 00114 for (Bitu x=0;x<rowsize;x++) mem_writeb(dest+x,mem_readb(src+x)); 00115 dest+=nextline;src+=nextline; 00116 } 00117 } 00118 00119 static void TEXT_CopyRow(Bit8u cleft,Bit8u cright,Bit8u rold,Bit8u rnew,PhysPt base) { 00120 PhysPt src,dest; 00121 src=base+(rold*CurMode->twidth+cleft)*2u; 00122 dest=base+(rnew*CurMode->twidth+cleft)*2u; 00123 MEM_BlockCopy(dest,src,(Bitu)(cright-cleft)*2u); 00124 } 00125 00126 static void PC98_CopyRow(Bit8u cleft,Bit8u cright,Bit8u rold,Bit8u rnew,PhysPt base) { 00127 PhysPt src,dest; 00128 00129 /* character data */ 00130 src=base+(rold*CurMode->twidth+cleft)*2; 00131 dest=base+(rnew*CurMode->twidth+cleft)*2; 00132 MEM_BlockCopy(dest,src,(Bitu)(cright-cleft)*2u); 00133 00134 /* attribute data */ 00135 MEM_BlockCopy(dest+0x2000,src+0x2000,(Bitu)(cright-cleft)*2u); 00136 } 00137 00138 static void MCGA2_FillRow(Bit8u cleft,Bit8u cright,Bit8u row,PhysPt base,Bit8u attr) { 00139 Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00140 PhysPt dest=base+((CurMode->twidth*row)*cheight+cleft); 00141 Bitu copy=(Bitu)(cright-cleft); 00142 Bitu nextline=CurMode->twidth; 00143 attr=(attr & 0x3) | ((attr & 0x3) << 2) | ((attr & 0x3) << 4) | ((attr & 0x3) << 6); 00144 for (Bitu i=0;i<cheight;i++) { 00145 for (Bitu x=0;x<copy;x++) { 00146 mem_writeb(dest+x,attr); 00147 } 00148 dest+=nextline; 00149 } 00150 } 00151 00152 static void CGA2_FillRow(Bit8u cleft,Bit8u cright,Bit8u row,PhysPt base,Bit8u attr) { 00153 Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00154 PhysPt dest=base+((CurMode->twidth*row)*(cheight/2)+cleft); 00155 Bitu copy=(Bitu)(cright-cleft); 00156 Bitu nextline=CurMode->twidth; 00157 attr=(attr & 0x3) | ((attr & 0x3) << 2) | ((attr & 0x3) << 4) | ((attr & 0x3) << 6); 00158 for (Bitu i=0;i<cheight/2U;i++) { 00159 for (Bitu x=0;x<copy;x++) { 00160 mem_writeb(dest+x,attr); 00161 mem_writeb(dest+8*1024+x,attr); 00162 } 00163 dest+=nextline; 00164 } 00165 } 00166 00167 static void CGA4_FillRow(Bit8u cleft,Bit8u cright,Bit8u row,PhysPt base,Bit8u attr) { 00168 Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00169 PhysPt dest=base+((CurMode->twidth*row)*(cheight/2)+cleft)*2; 00170 Bitu copy=(Bitu)(cright-cleft)*2u;Bitu nextline=CurMode->twidth*2; 00171 attr=(attr & 0x3) | ((attr & 0x3) << 2) | ((attr & 0x3) << 4) | ((attr & 0x3) << 6); 00172 for (Bitu i=0;i<cheight/2U;i++) { 00173 for (Bitu x=0;x<copy;x++) { 00174 mem_writeb(dest+x,attr); 00175 mem_writeb(dest+8*1024+x,attr); 00176 } 00177 dest+=nextline; 00178 } 00179 } 00180 00181 static void TANDY16_FillRow(Bit8u cleft,Bit8u cright,Bit8u row,PhysPt base,Bit8u attr) { 00182 Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00183 Bit8u banks=CurMode->twidth/10; 00184 PhysPt dest=base+((CurMode->twidth*row)*(cheight/banks)+cleft)*4; 00185 Bitu copy=(Bitu)(cright-cleft)*4u;Bitu nextline=CurMode->twidth*4; 00186 attr=(attr & 0xf) | (attr & 0xf) << 4; 00187 for (Bitu i=0;i<static_cast<Bitu>(cheight/banks);i++) { 00188 for (Bitu x=0;x<copy;x++) { 00189 for (Bitu b=0;b<banks;b++) mem_writeb(dest+b*8*1024+x,attr); 00190 } 00191 dest+=nextline; 00192 } 00193 } 00194 00195 static void EGA16_FillRow(Bit8u cleft,Bit8u cright,Bit8u row,PhysPt base,Bit8u attr) { 00196 /* Set Bitmask / Color / Full Set Reset */ 00197 IO_Write(0x3ce,0x8);IO_Write(0x3cf,0xff); 00198 IO_Write(0x3ce,0x0);IO_Write(0x3cf,attr); 00199 IO_Write(0x3ce,0x1);IO_Write(0x3cf,0xf); 00200 /* Enable all Write planes */ 00201 IO_Write(0x3c4,2);IO_Write(0x3c5,0xf); 00202 /* Write some bytes */ 00203 Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00204 PhysPt dest=base+(CurMode->twidth*row)*cheight+cleft; 00205 Bitu nextline=CurMode->twidth; 00206 Bitu copy = cheight;Bitu rowsize=(Bitu)(cright-cleft); 00207 for (;copy>0;copy--) { 00208 for (Bitu x=0;x<rowsize;x++) mem_writeb(dest+x,0xff); 00209 dest+=nextline; 00210 } 00211 IO_Write(0x3cf,0); 00212 } 00213 00214 static void VGA_FillRow(Bit8u cleft,Bit8u cright,Bit8u row,PhysPt base,Bit8u attr) { 00215 /* Write some bytes */ 00216 Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00217 PhysPt dest=base+8*((CurMode->twidth*row)*cheight+cleft); 00218 Bitu nextline=8*CurMode->twidth; 00219 Bitu copy = cheight;Bitu rowsize=8u*(Bitu)(cright-cleft); 00220 for (;copy>0;copy--) { 00221 for (Bitu x=0;x<rowsize;x++) mem_writeb(dest+x,attr); 00222 dest+=nextline; 00223 } 00224 } 00225 00226 static void PC98_FillRow(Bit8u cleft,Bit8u cright,Bit8u row,PhysPt base,Bit8u attr) { 00227 /* Do some filing */ 00228 PhysPt dest; 00229 dest=base+(row*CurMode->twidth+cleft)*2; 00230 Bit16u fill=' '; 00231 Bit16u fattr=attr ? attr : DefaultANSIAttr(); 00232 for (Bit8u x=0;x<(Bitu)(cright-cleft);x++) { 00233 mem_writew(dest,fill); 00234 mem_writew(dest+0x2000,fattr); 00235 dest+=2; 00236 } 00237 } 00238 00239 static void TEXT_FillRow(Bit8u cleft,Bit8u cright,Bit8u row,PhysPt base,Bit8u attr) { 00240 /* Do some filing */ 00241 PhysPt dest; 00242 dest=base+(row*CurMode->twidth+cleft)*2; 00243 Bit16u fill=(attr<<8)+' '; 00244 for (Bit8u x=0;x<(Bitu)(cright-cleft);x++) { 00245 mem_writew(dest,fill); 00246 dest+=2; 00247 } 00248 } 00249 00250 00251 void INT10_ScrollWindow(Bit8u rul,Bit8u cul,Bit8u rlr,Bit8u clr,Bit8s nlines,Bit8u attr,Bit8u page) { 00252 /* Do some range checking */ 00253 if (CurMode->type!=M_TEXT) page=0xff; 00254 BIOS_NCOLS;BIOS_NROWS; 00255 if(rul>rlr) return; 00256 if(cul>clr) return; 00257 if(rlr>=nrows) rlr=(Bit8u)nrows-1; 00258 if(clr>=ncols) clr=(Bit8u)ncols-1; 00259 clr++; 00260 00261 /* Get the correct page: current start address for current page (0xFF), 00262 otherwise calculate from page number and page size */ 00263 PhysPt base=CurMode->pstart; 00264 if (page==0xff) base+=real_readw(BIOSMEM_SEG,BIOSMEM_CURRENT_START); 00265 else base+=(unsigned int)page*real_readw(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE); 00266 00267 if (GCC_UNLIKELY(machine==MCH_PCJR)) { 00268 if (real_readb(BIOSMEM_SEG, BIOSMEM_CURRENT_MODE) >= 9) { 00269 // PCJr cannot handle these modes at 0xb800 00270 // See INT10_PutPixel M_TANDY16 00271 Bitu cpupage = 00272 (real_readb(BIOSMEM_SEG, BIOSMEM_CRTCPU_PAGE) >> 3) & 0x7; 00273 00274 base = cpupage << 14; 00275 if (page!=0xff) 00276 base += (unsigned int)page*real_readw(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE); 00277 } 00278 } 00279 00280 /* See how much lines need to be copied */ 00281 Bit8u start,end;Bits next; 00282 /* Copy some lines */ 00283 if (nlines>0) { 00284 start=rlr-nlines+1; 00285 end=rul; 00286 next=-1; 00287 } else if (nlines<0) { 00288 start=rul-nlines-1; 00289 end=rlr; 00290 next=1; 00291 } else { 00292 nlines=rlr-rul+1; 00293 goto filling; 00294 } 00295 while (start!=end) { 00296 start+=next; 00297 switch (CurMode->type) { 00298 case M_PC98: 00299 PC98_CopyRow(cul,clr,start,start+nlines,base);break; 00300 case M_TEXT: 00301 TEXT_CopyRow(cul,clr,start,start+nlines,base);break; 00302 case M_CGA2: 00303 if (machine == MCH_MCGA && CurMode->mode == 0x11) 00304 MCGA2_CopyRow(cul,clr,start,start+nlines,base); 00305 else 00306 CGA2_CopyRow(cul,clr,start,start+nlines,base); 00307 break; 00308 case M_CGA4: 00309 CGA4_CopyRow(cul,clr,start,start+nlines,base);break; 00310 case M_TANDY16: 00311 TANDY16_CopyRow(cul,clr,start,start+nlines,base);break; 00312 case M_EGA: 00313 EGA16_CopyRow(cul,clr,start,start+nlines,base);break; 00314 case M_VGA: 00315 VGA_CopyRow(cul,clr,start,start+nlines,base);break; 00316 case M_LIN4: 00317 if ((machine==MCH_VGA) && (svgaCard==SVGA_TsengET4K) && 00318 (CurMode->swidth<=800)) { 00319 // the ET4000 BIOS supports text output in 800x600 SVGA 00320 EGA16_CopyRow(cul,clr,start,start+nlines,base);break; 00321 } 00322 // fall-through 00323 default: 00324 LOG(LOG_INT10,LOG_ERROR)("Unhandled mode %d for scroll",CurMode->type); 00325 } 00326 } 00327 /* Fill some lines */ 00328 filling: 00329 if (nlines>0) { 00330 start=rul; 00331 } else { 00332 nlines=-nlines; 00333 start=rlr-nlines+1; 00334 } 00335 for (;nlines>0;nlines--) { 00336 switch (CurMode->type) { 00337 case M_PC98: 00338 PC98_FillRow(cul,clr,start,base,attr);break; 00339 case M_TEXT: 00340 TEXT_FillRow(cul,clr,start,base,attr);break; 00341 case M_CGA2: 00342 if (machine == MCH_MCGA && CurMode->mode == 0x11) 00343 MCGA2_FillRow(cul,clr,start,base,attr); 00344 else 00345 CGA2_FillRow(cul,clr,start,base,attr); 00346 break; 00347 case M_CGA4: 00348 CGA4_FillRow(cul,clr,start,base,attr);break; 00349 case M_TANDY16: 00350 TANDY16_FillRow(cul,clr,start,base,attr);break; 00351 case M_EGA: 00352 EGA16_FillRow(cul,clr,start,base,attr);break; 00353 case M_VGA: 00354 VGA_FillRow(cul,clr,start,base,attr);break; 00355 case M_LIN4: 00356 if ((machine==MCH_VGA) && (svgaCard==SVGA_TsengET4K) && 00357 (CurMode->swidth<=800)) { 00358 EGA16_FillRow(cul,clr,start,base,attr);break; 00359 } 00360 // fall-through 00361 default: 00362 LOG(LOG_INT10,LOG_ERROR)("Unhandled mode %d for scroll",CurMode->type); 00363 } 00364 start++; 00365 } 00366 } 00367 00368 void INT10_SetActivePage(Bit8u page) { 00369 Bit16u mem_address; 00370 if (page>7) LOG(LOG_INT10,LOG_ERROR)("INT10_SetActivePage page %d",page); 00371 00372 if (IS_EGAVGA_ARCH && (svgaCard==SVGA_S3Trio)) page &= 7; 00373 00374 mem_address=page*real_readw(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE); 00375 /* Write the new page start */ 00376 real_writew(BIOSMEM_SEG,BIOSMEM_CURRENT_START,mem_address); 00377 if (IS_EGAVGA_ARCH) { 00378 if (CurMode->mode<8) mem_address>>=1; 00379 // rare alternative: if (CurMode->type==M_TEXT) mem_address>>=1; 00380 } else { 00381 mem_address>>=1; 00382 } 00383 /* Write the new start address in vgahardware */ 00384 Bit16u base=real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); 00385 IO_Write(base,0x0cu); 00386 IO_Write(base+1u,(Bit8u)(mem_address>>8u)); 00387 IO_Write(base,0x0du); 00388 IO_Write(base+1u,(Bit8u)mem_address); 00389 00390 // And change the BIOS page 00391 real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE,page); 00392 Bit8u cur_row=CURSOR_POS_ROW(page); 00393 Bit8u cur_col=CURSOR_POS_COL(page); 00394 // Display the cursor, now the page is active 00395 INT10_SetCursorPos(cur_row,cur_col,page); 00396 } 00397 00398 void INT10_SetCursorShape(Bit8u first,Bit8u last) { 00399 real_writew(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE,last|(first<<8u)); 00400 if (machine==MCH_CGA || machine==MCH_MCGA || machine==MCH_AMSTRAD) goto dowrite; 00401 if (IS_TANDY_ARCH) goto dowrite; 00402 /* Skip CGA cursor emulation if EGA/VGA system is active */ 00403 if (!(real_readb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL) & 0x8)) { 00404 /* Check for CGA type 01, invisible */ 00405 if ((first & 0x60) == 0x20) { 00406 first=0x1e; 00407 last=0x00; 00408 goto dowrite; 00409 } 00410 /* Check if we need to convert CGA Bios cursor values */ 00411 if (!(real_readb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL) & 0x1)) { // set by int10 fun12 sub34 00412 // if (CurMode->mode>0x3) goto dowrite; //Only mode 0-3 are text modes on cga 00413 if ((first & 0xe0) || (last & 0xe0)) goto dowrite; 00414 Bit8u cheight=real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)-1; 00415 /* Creative routine i based of the original ibmvga bios */ 00416 00417 if (last<first) { 00418 if (!last) goto dowrite; 00419 first=last; 00420 last=cheight; 00421 /* Test if this might be a cga style cursor set, if not don't do anything */ 00422 } else if (((first | last)>=cheight) || !(last==(cheight-1)) || !(first==cheight) ) { 00423 if (last<=3) goto dowrite; 00424 if (first+2<last) { 00425 if (first>2) { 00426 first=(cheight+1)/2; 00427 last=cheight; 00428 } else { 00429 last=cheight; 00430 } 00431 } else { 00432 first=(first-last)+cheight; 00433 last=cheight; 00434 00435 if (cheight>0xc) { // vgatest sets 15 15 2x where only one should be decremented to 14 14 00436 first--; // implementing int10 fun12 sub34 fixed this. 00437 last--; 00438 } 00439 } 00440 } 00441 00442 } 00443 } 00444 dowrite: 00445 Bit16u base=real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); 00446 IO_Write(base,0xa);IO_Write(base+1u,first); 00447 IO_Write(base,0xb);IO_Write(base+1u,last); 00448 } 00449 00450 void vga_pc98_direct_cursor_pos(Bit16u address); 00451 00452 void INT10_GetScreenColumns(Bit16u *cols) 00453 { 00454 if (IS_PC98_ARCH) 00455 *cols = 80; //TODO 00456 else 00457 *cols = real_readw(BIOSMEM_SEG, BIOSMEM_NB_COLS); 00458 } 00459 00460 void INT10_GetCursorPos(Bit8u *row, Bit8u*col, const Bit8u page) 00461 { 00462 if (IS_PC98_ARCH) { 00463 *col = real_readb(0x60, 0x11C); 00464 *row = real_readb(0x60, 0x110); 00465 } 00466 else { 00467 *col = real_readb(BIOSMEM_SEG, BIOSMEM_CURSOR_POS + page * 2u); 00468 *row = real_readb(BIOSMEM_SEG, BIOSMEM_CURSOR_POS + page * 2u + 1u); 00469 } 00470 } 00471 00472 void INT10_SetCursorPos(Bit8u row,Bit8u col,Bit8u page) { 00473 if (page>7) LOG(LOG_INT10,LOG_ERROR)("INT10_SetCursorPos page %d",page); 00474 // Bios cursor pos 00475 if (IS_PC98_ARCH) { 00476 real_writeb(0x60,0x11C,col); 00477 real_writeb(0x60,0x110,row); 00478 page = 0; 00479 } 00480 else { 00481 real_writeb(BIOSMEM_SEG,BIOSMEM_CURSOR_POS+page*2u,col); 00482 real_writeb(BIOSMEM_SEG,BIOSMEM_CURSOR_POS+page*2u+1u,row); 00483 } 00484 // Set the hardware cursor 00485 Bit8u current=IS_PC98_ARCH ? 0 : real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00486 if(page==current) { 00487 // Get the dimensions 00488 BIOS_NCOLS; 00489 // Calculate the address knowing nbcols nbrows and page num 00490 // NOTE: BIOSMEM_CURRENT_START counts in colour/flag pairs 00491 Bit16u address=(ncols*row)+col+(IS_PC98_ARCH ? 0 : (real_readw(BIOSMEM_SEG,BIOSMEM_CURRENT_START)/2)); 00492 if (IS_PC98_ARCH) { 00493 vga_pc98_direct_cursor_pos(address); 00494 } 00495 else { 00496 // CRTC regs 0x0e and 0x0f 00497 Bit16u base=real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); 00498 IO_Write(base,0x0eu); 00499 IO_Write(base+1u,(Bit8u)(address>>8u)); 00500 IO_Write(base,0x0fu); 00501 IO_Write(base+1u,(Bit8u)address); 00502 } 00503 } 00504 } 00505 00506 void ReadCharAttr(Bit16u col,Bit16u row,Bit8u page,Bit16u * result) { 00507 /* Externally used by the mouse routine */ 00508 PhysPt fontdata; 00509 Bit16u cols = real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); 00510 Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00511 bool split_chr = false; 00512 switch (CurMode->type) { 00513 case M_TEXT: 00514 { 00515 // Compute the address 00516 Bit16u address=page*real_readw(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE); 00517 address+=(row*cols+col)*2; 00518 // read the char 00519 PhysPt where = CurMode->pstart+address; 00520 *result=mem_readw(where); 00521 } 00522 return; 00523 case M_CGA4: 00524 case M_CGA2: 00525 case M_TANDY16: 00526 split_chr = true; 00527 switch (machine) { 00528 case MCH_CGA: 00529 case MCH_HERC: 00530 fontdata=PhysMake(0xf000,0xfa6e); 00531 break; 00532 case TANDY_ARCH_CASE: 00533 fontdata=Real2Phys(RealGetVec(0x44)); 00534 break; 00535 default: 00536 fontdata=Real2Phys(RealGetVec(0x43)); 00537 break; 00538 } 00539 break; 00540 default: 00541 fontdata=Real2Phys(RealGetVec(0x43)); 00542 break; 00543 } 00544 00545 Bitu x=col*8u,y=(unsigned int)row*cheight*(cols/CurMode->twidth); 00546 00547 for (Bit16u chr=0;chr<256;chr++) { 00548 00549 if (chr==128 && split_chr) fontdata=Real2Phys(RealGetVec(0x1f)); 00550 00551 bool error=false; 00552 Bit16u ty=(Bit16u)y; 00553 for (Bit8u h=0;h<cheight;h++) { 00554 Bit8u bitsel=128; 00555 Bit8u bitline=mem_readb(fontdata++); 00556 Bit8u res=0; 00557 Bit8u vidline=0; 00558 Bit16u tx=(Bit16u)x; 00559 while (bitsel) { 00560 //Construct bitline in memory 00561 INT10_GetPixel(tx,ty,page,&res); 00562 if(res) vidline|=bitsel; 00563 tx++; 00564 bitsel>>=1; 00565 } 00566 ty++; 00567 if(bitline != vidline){ 00568 /* It's not character 'chr', move on to the next */ 00569 fontdata+=(unsigned int)(cheight-(unsigned int)h-1u); 00570 error = true; 00571 break; 00572 } 00573 } 00574 if(!error){ 00575 /* We found it */ 00576 *result = chr; 00577 return; 00578 } 00579 } 00580 LOG(LOG_INT10,LOG_ERROR)("ReadChar didn't find character"); 00581 *result = 0; 00582 } 00583 void INT10_ReadCharAttr(Bit16u * result,Bit8u page) { 00584 if(page==0xFF) page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00585 Bit8u cur_row=CURSOR_POS_ROW(page); 00586 Bit8u cur_col=CURSOR_POS_COL(page); 00587 ReadCharAttr(cur_col,cur_row,page,result); 00588 } 00589 00590 void INT10_PC98_CurMode_Relocate(void) { 00591 /* deprecated */ 00592 } 00593 00594 void WriteChar(Bit16u col,Bit16u row,Bit8u page,Bit16u chr,Bit8u attr,bool useattr) { 00595 /* Externally used by the mouse routine */ 00596 PhysPt fontdata; 00597 Bit16u cols = real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); 00598 Bit8u back, cheight = IS_PC98_ARCH ? 16 : real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); 00599 00600 if (CurMode->type != M_PC98) 00601 chr &= 0xFF; 00602 00603 switch (CurMode->type) { 00604 case M_TEXT: 00605 { 00606 // Compute the address 00607 Bit16u address=page*real_readw(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE); 00608 address+=(row*cols+col)*2; 00609 // Write the char 00610 PhysPt where = CurMode->pstart+address; 00611 mem_writeb(where,chr); 00612 if (useattr) mem_writeb(where+1,attr); 00613 } 00614 return; 00615 case M_PC98: 00616 { 00617 // Compute the address 00618 Bit16u address=((row*80)+col)*2; 00619 // Write the char 00620 PhysPt where = CurMode->pstart+address; 00621 mem_writew(where,chr); 00622 if (useattr) { 00623 mem_writeb(where+0x2000,attr); 00624 } 00625 00626 // some chars are double-wide and need to fill both cells. 00627 // however xx08h-xx0Bh are single-wide encodings such as the 00628 // single-wide box characters used by DOSBox-X's introductory 00629 // message. 00630 if ((chr & 0xFF00u) != 0u && (chr & 0xFCu) != 0x08u) { 00631 where += 2u; 00632 mem_writew(where,chr); 00633 if (useattr) { 00634 mem_writeb(where+0x2000,attr); 00635 } 00636 } 00637 } 00638 return; 00639 case M_CGA4: 00640 case M_CGA2: 00641 case M_TANDY16: 00642 if (chr>=128) { 00643 chr-=128; 00644 fontdata=Real2Phys(RealGetVec(0x1f)); 00645 break; 00646 } 00647 switch (machine) { 00648 case MCH_CGA: 00649 case MCH_HERC: 00650 fontdata=PhysMake(0xf000,0xfa6e); 00651 break; 00652 case TANDY_ARCH_CASE: 00653 fontdata=Real2Phys(RealGetVec(0x44)); 00654 break; 00655 default: 00656 fontdata=Real2Phys(RealGetVec(0x43)); 00657 break; 00658 } 00659 break; 00660 default: 00661 fontdata=Real2Phys(RealGetVec(0x43)); 00662 break; 00663 } 00664 fontdata+=(unsigned int)chr*(unsigned int)cheight; 00665 00666 if(GCC_UNLIKELY(!useattr)) { //Set attribute(color) to a sensible value 00667 static bool warned_use = false; 00668 if(GCC_UNLIKELY(!warned_use)){ 00669 LOG(LOG_INT10,LOG_ERROR)("writechar used without attribute in non-textmode %c %X",chr,chr); 00670 warned_use = true; 00671 } 00672 switch(CurMode->type) { 00673 case M_CGA4: 00674 attr = 0x3; 00675 break; 00676 case M_CGA2: 00677 attr = 0x1; 00678 break; 00679 case M_TANDY16: 00680 case M_EGA: 00681 default: 00682 attr = 0x7; 00683 break; 00684 } 00685 } 00686 00687 //Attribute behavior of mode 6; mode 11 does something similar but 00688 //it is in INT 10h handler because it only applies to function 09h 00689 if (CurMode->mode==0x06) attr=(attr&0x80)|1; 00690 00691 switch (CurMode->type) { 00692 case M_VGA: 00693 case M_LIN8: 00694 // 256-color modes have background color instead of page 00695 back=page; 00696 page=0; 00697 break; 00698 case M_EGA: 00699 /* enable all planes for EGA modes (Ultima 1 colour bug) */ 00700 /* might be put into INT10_PutPixel but different vga bios 00701 implementations have different opinions about this */ 00702 IO_Write(0x3c4,0x2);IO_Write(0x3c5,0xf); 00703 /* fall through */ 00704 default: 00705 back=attr&0x80; 00706 break; 00707 } 00708 00709 Bitu x=col*8u,y=(unsigned int)(row*(unsigned int)cheight*(cols/CurMode->twidth)); 00710 00711 Bit16u ty=(Bit16u)y; 00712 for (Bit8u h=0;h<cheight;h++) { 00713 Bit8u bitsel=128; 00714 Bit8u bitline=mem_readb(fontdata++); 00715 Bit16u tx=(Bit16u)x; 00716 while (bitsel) { 00717 INT10_PutPixel(tx,ty,page,(bitline&bitsel)?attr:back); 00718 tx++; 00719 bitsel>>=1; 00720 } 00721 ty++; 00722 } 00723 } 00724 00725 void INT10_WriteChar(Bit16u chr,Bit8u attr,Bit8u page,Bit16u count,bool showattr) { 00726 Bit8u pospage=page; 00727 if (CurMode->type!=M_TEXT) { 00728 showattr=true; //Use attr in graphics mode always 00729 switch (machine) { 00730 case EGAVGA_ARCH_CASE: 00731 switch (CurMode->type) { 00732 case M_VGA: 00733 case M_LIN8: 00734 pospage=0; 00735 break; 00736 default: 00737 page%=CurMode->ptotal; 00738 pospage=page; 00739 break; 00740 } 00741 break; 00742 case MCH_CGA: 00743 case MCH_MCGA: 00744 case MCH_PCJR: 00745 page=0; 00746 pospage=0; 00747 break; 00748 default: 00749 break; 00750 } 00751 } 00752 00753 Bit8u cur_row=CURSOR_POS_ROW(pospage); 00754 Bit8u cur_col=CURSOR_POS_COL(pospage); 00755 BIOS_NCOLS; 00756 while (count>0) { 00757 WriteChar(cur_col,cur_row,page,chr,attr,showattr); 00758 count--; 00759 cur_col++; 00760 if(cur_col==ncols) { 00761 cur_col=0; 00762 cur_row++; 00763 } 00764 } 00765 00766 if (CurMode->type==M_EGA) { 00767 // Reset write ops for EGA graphics modes 00768 IO_Write(0x3ce,0x3);IO_Write(0x3cf,0x0); 00769 } 00770 } 00771 00772 static void INT10_TeletypeOutputAttr(Bit8u chr,Bit8u attr,bool useattr,Bit8u page) { 00773 BIOS_NCOLS;BIOS_NROWS; 00774 Bit8u cur_row=CURSOR_POS_ROW(page); 00775 Bit8u cur_col=CURSOR_POS_COL(page); 00776 switch (chr) { 00777 case 8: 00778 if(cur_col>0) cur_col--; 00779 break; 00780 case '\r': 00781 cur_col=0; 00782 break; 00783 case '\n': 00784 // cur_col=0; //Seems to break an old chess game 00785 cur_row++; 00786 break; 00787 case 7: /* Beep */ 00788 // Prepare PIT counter 2 for ~900 Hz square wave 00789 IO_Write(0x43, 0xb6); 00790 IO_Write(0x42, 0x28); 00791 IO_Write(0x42, 0x05); 00792 // Speaker on 00793 IO_Write(0x61, IO_Read(0x61) | 0x3); 00794 // Idle for 1/3rd of a second 00795 double start; 00796 start = PIC_FullIndex(); 00797 while ((PIC_FullIndex() - start) < 333.0) CALLBACK_Idle(); 00798 // Speaker off 00799 IO_Write(0x61, IO_Read(0x61) & ~0x3); 00800 chr=' '; 00801 default: 00802 /* Draw the actual Character */ 00803 WriteChar(cur_col,cur_row,page,chr,attr,useattr); 00804 cur_col++; 00805 } 00806 if(cur_col==ncols) { 00807 cur_col=0; 00808 cur_row++; 00809 } 00810 // Do we need to scroll ? 00811 if(cur_row==nrows) { 00812 //Fill with black on non-text modes 00813 Bit8u fill = 0; 00814 if (IS_PC98_ARCH && CurMode->type == M_TEXT) { 00815 //Fill with the default ANSI attribute on textmode 00816 fill = DefaultANSIAttr(); 00817 } 00818 else if (CurMode->type==M_TEXT) { 00819 //Fill with attribute at cursor on textmode 00820 Bit16u chat; 00821 INT10_ReadCharAttr(&chat,page); 00822 fill=(Bit8u)(chat>>8); 00823 } 00824 INT10_ScrollWindow(0,0,(Bit8u)(nrows-1),(Bit8u)(ncols-1),-1,fill,page); 00825 cur_row--; 00826 } 00827 // Set the cursor for the page 00828 INT10_SetCursorPos(cur_row,cur_col,page); 00829 } 00830 00831 void INT10_TeletypeOutputAttr(Bit8u chr,Bit8u attr,bool useattr) { 00832 INT10_TeletypeOutputAttr(chr,attr,useattr,real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); 00833 } 00834 00835 void INT10_TeletypeOutput(Bit8u chr,Bit8u attr) { 00836 INT10_TeletypeOutputAttr(chr,attr,CurMode->type!=M_TEXT); 00837 } 00838 00839 void INT10_WriteString(Bit8u row,Bit8u col,Bit8u flag,Bit8u attr,PhysPt string,Bit16u count,Bit8u page) { 00840 Bit8u cur_row=CURSOR_POS_ROW(page); 00841 Bit8u cur_col=CURSOR_POS_COL(page); 00842 00843 // if row=0xff special case : use current cursor position 00844 if (row==0xff) { 00845 row=cur_row; 00846 col=cur_col; 00847 } 00848 INT10_SetCursorPos(row,col,page); 00849 while (count>0) { 00850 Bit8u chr=mem_readb(string); 00851 string++; 00852 if (flag&2) { 00853 attr=mem_readb(string); 00854 string++; 00855 } 00856 INT10_TeletypeOutputAttr(chr,attr,true,page); 00857 count--; 00858 } 00859 if (!(flag&1)) { 00860 INT10_SetCursorPos(cur_row,cur_col,page); 00861 } 00862 } 00863 00864 bool pc98_doskey_insertmode = false; 00865 00866 bool INT10_GetInsertState() 00867 { 00868 if (IS_PC98_ARCH) { 00869 /* state is internal to DOSKEY */ 00870 return pc98_doskey_insertmode; 00871 } 00872 else { 00873 const auto flags = mem_readb(BIOS_KEYBOARD_FLAGS1); 00874 const auto state =static_cast<bool>(flags & BIOS_KEYBOARD_FLAGS1_INSERT_ACTIVE); 00875 return state; 00876 } 00877 }