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