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