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