DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/ints/int10_misc.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #include "dosbox.h"
00021 #include "mem.h"
00022 #include "inout.h"
00023 #include "int10.h"
00024 
00025 
00026 
00027 #pragma pack(1)
00028 struct Dynamic_Functionality {
00029         RealPt static_table;            /* 00h   DWORD  address of static functionality table */
00030         Bit8u cur_mode;                         /* 04h   BYTE   video mode in effect */
00031         Bit16u num_cols;                        /* 05h   WORD   number of columns */
00032         Bit16u regen_size;                      /* 07h   WORD   length of regen buffer in bytes */
00033         Bit16u regen_start;                     /* 09h   WORD   starting address of regen buffer*/
00034         Bit16u cursor_pos[8];           /* 0Bh   WORD   cursor position for page 0-7 */
00035         Bit16u cursor_type;                     /* 1Bh   WORD   cursor type */
00036         Bit8u active_page;                      /* 1Dh   BYTE   active display page */
00037         Bit16u crtc_address;            /* 1Eh   WORD   CRTC port address */
00038         Bit8u reg_3x8;                          /* 20h   BYTE   current setting of register (3?8) */
00039         Bit8u reg_3x9;                          /* 21h   BYTE   current setting of register (3?9) */
00040         Bit8u num_rows;                         /* 22h   BYTE   number of rows */
00041         Bit16u bytes_per_char;          /* 23h   WORD   bytes/character */
00042         Bit8u dcc;                                      /* 25h   BYTE   display combination code of active display */
00043         Bit8u dcc_alternate;            /* 26h   BYTE   DCC of alternate display */
00044         Bit16u num_colors;                      /* 27h   WORD   number of colors supported in current mode */
00045         Bit8u num_pages;                        /* 29h   BYTE   number of pages supported in current mode */
00046         Bit8u num_scanlines;            /* 2Ah   BYTE   number of scan lines active mode (0,1,2,3) = (200,350,400,480) */
00047         Bit8u pri_char_block;           /* 2Bh   BYTE   primary character block */
00048         Bit8u sec_char_block;           /* 2Ch   BYTE   secondary character block */
00049         Bit8u misc_flags;                       /* 2Dh   BYTE   miscellaneous flags
00050                                                                         bit 0 all modes on all displays on
00051                                                                         1 grey summing on
00052                                                                         2 monochrome display attached
00053                                                                         3 default palette loading disabled
00054                                                                         4 cursor emulation enabled
00055                                                                         5 0 = intensity; 1 = blinking
00056                                                                         6 PS/2 P70 plasma display (without 9-dot wide font) active
00057                                                                         7 reserved
00058                                                                 */
00059         Bit8u reserved1[3];                     /* 2Eh  3 BYTEs reserved (00h) */
00060         Bit8u vid_mem;                          /* 31h   BYTE   video memory available 00h = 64K, 01h = 128K, 02h = 192K, 03h = 256K */
00061         Bit8u savep_state_flag;         /* 32h   BYTE   save pointer state flags 
00062                                                                         bit 0 512 character set active
00063                                                                         1 dynamic save area present
00064                                                                         2 alpha font override active
00065                                                                         3 graphics font override active
00066                                                                         4 palette override active
00067                                                                         5 DCC override active
00068                                                                         6 reserved
00069                                                                         7 reserved
00070                                                                 */
00071         Bit8u reserved2[13];            /*  33h 13 BYTEs reserved (00h) */
00072 } GCC_ATTRIBUTE(packed);
00073 #pragma pack()
00074 
00075 void INT10_DisplayCombinationCode(Bit16u * dcc,bool set) {
00076     // FIXME
00077     if (machine == MCH_MCGA) {
00078         *dcc = 0x0C; // MCGA color analogue display
00079         return;
00080     }
00081 
00082         Bit8u index=0xff;
00083         Bit16u dccentry=0xffff;
00084         // walk the tables...
00085         RealPt vsavept=real_readd(BIOSMEM_SEG,BIOSMEM_VS_POINTER);
00086         RealPt svstable=real_readd(RealSeg(vsavept),RealOff(vsavept)+0x10);
00087         if (svstable) {
00088                 RealPt dcctable=real_readd(RealSeg(svstable),RealOff(svstable)+0x02);
00089                 Bit8u entries=real_readb(RealSeg(dcctable),RealOff(dcctable)+0x00);
00090                 if (set) {
00091                         if (entries) {
00092                                 Bit16u swap=(*dcc<<8)|(*dcc>>8);
00093                                 // search for the index in the dcc table
00094                                 for (Bit8u entry=0; entry<entries; entry++) {
00095                                         dccentry=real_readw(RealSeg(dcctable),RealOff(dcctable)+0x04+entry*2);
00096                                         if ((dccentry==*dcc) || (dccentry==swap)) {
00097                                                 index=entry;
00098                                                 break;
00099                                         }
00100                                 }
00101                         }
00102                 } else {
00103                         index=real_readb(BIOSMEM_SEG,BIOSMEM_DCC_INDEX);
00104                         // check if index within range
00105                         if (index<entries) {
00106                                 dccentry=real_readw(RealSeg(dcctable),RealOff(dcctable)+0x04+index*2);
00107                                 if ((dccentry&0xff)==0) dccentry>>=8;
00108                                 else if (dccentry>>8) {
00109                                         Bit16u cfg_mono=((real_readw(BIOSMEM_SEG,BIOSMEM_INITIAL_MODE)&0x30)==0x30)?1:0;
00110                                         if (cfg_mono^(dccentry&1)) dccentry=(dccentry<<8)|(dccentry>>8);
00111                                 }
00112                         }
00113                 }
00114         }
00115         if (set) real_writeb(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,index);
00116         else *dcc=dccentry;
00117 }
00118 
00119 void INT10_GetFuncStateInformation(PhysPt save) {
00120         /* set static state pointer */
00121         mem_writed(save,int10.rom.static_state);
00122         /* Copy BIOS Segment areas */
00123         Bit16u i;
00124 
00125         /* First area in Bios Seg */
00126         for (i=0;i<0x1e;i++) {
00127                 mem_writeb(save+0x4+i,real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE+i));
00128         }
00129         /* Second area */
00130         mem_writeb(save+0x22,real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1);
00131         for (i=1;i<3;i++) {
00132                 mem_writeb(save+0x22+i,real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS+i));
00133         }
00134         /* Zero out rest of block */
00135         for (i=0x25;i<0x40;i++) mem_writeb(save+i,0);
00136         /* DCC */
00137         Bit16u dcc=0;
00138         INT10_DisplayCombinationCode(&dcc,false);
00139         mem_writew(save+0x25,dcc);
00140 
00141         Bit16u col_count=0;
00142         switch (CurMode->type) {
00143         case M_TEXT:
00144                 if (CurMode->mode==0x7) col_count=1; else col_count=16;break; 
00145         case M_CGA2:
00146                 col_count=2;break;
00147         case M_CGA4:
00148                 col_count=4;break;
00149         case M_EGA:
00150                 if (CurMode->mode==0x11 || CurMode->mode==0x0f) 
00151                         col_count=2; 
00152                 else 
00153                         col_count=16;
00154                 break; 
00155         case M_VGA:
00156                 col_count=256;break;
00157         default:
00158                 LOG(LOG_INT10,LOG_ERROR)("Get Func State illegal mode type %d",CurMode->type);
00159         }
00160         /* Colour count */
00161         mem_writew(save+0x27,col_count);
00162         /* Page count */
00163         mem_writeb(save+0x29,(Bit8u)CurMode->ptotal);
00164         /* scan lines */
00165         switch (CurMode->sheight) {
00166         case 200:
00167                 mem_writeb(save+0x2a,0);break;
00168         case 350:
00169                 mem_writeb(save+0x2a,1);break;
00170         case 400:
00171                 mem_writeb(save+0x2a,2);break;
00172         case 480:
00173                 mem_writeb(save+0x2a,3);break;
00174         }
00175         /* misc flags */
00176         if (CurMode->type==M_TEXT) mem_writeb(save+0x2d,0x21);
00177         else mem_writeb(save+0x2d,0x01);
00178         /* Video Memory available */
00179         mem_writeb(save+0x31,3);
00180 }
00181 
00182 RealPt INT10_EGA_RIL_GetVersionPt(void) {
00183         /* points to a graphics ROM location at the moment
00184            as checks test for bx!=0 only */
00185         return RealMake(0xc000,0x30);
00186 }
00187 
00188 static void EGA_RIL(Bit16u dx, Bit16u& port, Bit16u& regs) {
00189         port = 0;
00190         regs = 0; //if nul is returned it's a single register port
00191         switch(dx) {
00192         case 0x00: /* CRT Controller (25 reg) 3B4h mono modes, 3D4h color modes */
00193                 port = real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
00194                 regs = 25;
00195                 break;
00196         case 0x08: /* Sequencer (5 registers) 3C4h */
00197                 port = 0x3C4;
00198                 regs = 5;
00199                 break;
00200         case 0x10: /* Graphics Controller (9 registers) 3CEh */
00201                 port = 0x3CE;
00202                 regs = 9;
00203                 break;
00204         case 0x18: /* Attribute Controller (20 registers) 3C0h */
00205                 port = 0x3c0;
00206                 regs = 20;
00207                 break;
00208         case 0x20: /* Miscellaneous Output register 3C2h */
00209                 port = 0x3C2;
00210                 break;
00211         case 0x28: /* Feature Control register (3BAh mono modes, 3DAh color modes) */
00212                 port = real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6u;
00213                 break;
00214         case 0x30: /* Graphics 1 Position register 3CCh */
00215                 port = 0x3CC;
00216                 break;
00217         case 0x38: /* Graphics 2 Position register 3CAh */
00218                 port = 0x3CA;
00219                 break;
00220         default:
00221                 LOG(LOG_INT10,LOG_ERROR)("unknown RIL port selection %X",dx);
00222                 break;
00223         }
00224 }
00225 
00226 void INT10_EGA_RIL_ReadRegister(Bit8u & bl, Bit16u dx) {
00227         Bit16u port = 0;
00228         Bit16u regs = 0;
00229         EGA_RIL(dx,port,regs);
00230         if(regs == 0) {
00231                 if(port) bl = IO_Read(port);
00232         } else {
00233                 if(port == 0x3c0) IO_Read(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6u);
00234                 IO_Write(port,bl);
00235                 bl = IO_Read(port+1u);
00236                 if(port == 0x3c0) IO_Read(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6u);
00237                 LOG(LOG_INT10,LOG_NORMAL)("EGA RIL read used with multi-reg");
00238         }
00239 }
00240 
00241 void INT10_EGA_RIL_WriteRegister(Bit8u & bl, Bit8u bh, Bit16u dx) {
00242         Bit16u port = 0;
00243         Bit16u regs = 0;
00244         EGA_RIL(dx,port,regs);
00245         if(regs == 0) {
00246                 if(port) IO_Write(port,bl);
00247         } else {
00248                 if(port == 0x3c0) {
00249                         IO_Read(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6u);
00250                         IO_Write(port,bl);
00251                         IO_Write(port,bh);
00252                 } else {
00253                         IO_Write(port,bl);
00254                         IO_Write(port+1u,bh);
00255                 }
00256                 bl = bh;//Not sure
00257                 LOG(LOG_INT10,LOG_NORMAL)("EGA RIL write used with multi-reg");
00258         }
00259 }
00260 
00261 void INT10_EGA_RIL_ReadRegisterRange(Bit8u ch, Bit8u cl, Bit16u dx, PhysPt dst) {
00262         Bit16u port = 0;
00263         Bit16u regs = 0;
00264         EGA_RIL(dx,port,regs);
00265         if(regs == 0) {
00266                 LOG(LOG_INT10,LOG_ERROR)("EGA RIL range read with port %x called",(int)port);
00267         } else {
00268                 if(ch<regs) {
00269                         if ((Bitu)ch+cl>regs) cl=(Bit8u)(regs-ch);
00270                         for (Bitu i=0; i<cl; i++) {
00271                                 if(port == 0x3c0) IO_Read(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6u);
00272                                 IO_Write(port,(Bit8u)(ch+i));
00273                                 mem_writeb(dst++,IO_Read(port+1u));
00274                         }
00275                         if(port == 0x3c0) IO_Read(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6u);
00276                 } else LOG(LOG_INT10,LOG_ERROR)("EGA RIL range read from %x for invalid register %x",(int)port,(int)ch);
00277         }
00278 }
00279 
00280 void INT10_EGA_RIL_WriteRegisterRange(Bit8u ch, Bit8u cl, Bit16u dx, PhysPt src) {
00281         Bit16u port = 0;
00282         Bit16u regs = 0;
00283         EGA_RIL(dx,port,regs);
00284         if(regs == 0) {
00285                 LOG(LOG_INT10,LOG_ERROR)("EGA RIL range write called with port %x",(int)port);
00286         } else {
00287                 if(ch<regs) {
00288                         if ((Bitu)ch+cl>regs) cl=(Bit8u)(regs-ch);
00289                         if(port == 0x3c0) {
00290                                 IO_Read(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6u);
00291                                 for (Bitu i=0; i<cl; i++) {
00292                                         IO_Write(port,(Bit8u)(ch+i));
00293                                         IO_Write(port,mem_readb(src++));
00294                                 }
00295                         } else {
00296                                 for (Bitu i=0; i<cl; i++) {
00297                                         IO_Write(port,(Bit8u)(ch+i));
00298                                         IO_Write(port+1u,mem_readb(src++));
00299                                 }
00300                         }
00301                 } else LOG(LOG_INT10,LOG_ERROR)("EGA RIL range write to %x with invalid register %x",(int)port,(int)ch);
00302         }
00303 }
00304 
00305 /* register sets are of the form
00306    offset 0 (word): group index
00307    offset 2 (byte): register number (0 for single registers, ignored)
00308    offset 3 (byte): register value (return value when reading)
00309 */
00310 void INT10_EGA_RIL_ReadRegisterSet(Bit16u cx, PhysPt tbl) {
00311         /* read cx register sets */
00312         for (Bit16u i=0; i<cx; i++) {
00313                 Bit8u vl=mem_readb(tbl+2);
00314                 INT10_EGA_RIL_ReadRegister(vl, mem_readw(tbl));
00315                 mem_writeb(tbl+3, vl);
00316                 tbl+=4;
00317         }
00318 }
00319 
00320 void INT10_EGA_RIL_WriteRegisterSet(Bit16u cx, PhysPt tbl) {
00321         /* write cx register sets */
00322         Bit16u port = 0;
00323         Bit16u regs = 0;
00324         for (Bit16u i=0; i<cx; i++) {
00325                 EGA_RIL(mem_readw(tbl),port,regs);
00326                 Bit8u vl=mem_readb(tbl+3);
00327                 if(regs == 0) {
00328                         if(port) IO_Write(port,vl);
00329                 } else {
00330                         Bit8u idx=mem_readb(tbl+2);
00331                         if(port == 0x3c0) {
00332                                 IO_Read(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6u);
00333                                 IO_Write(port,idx);
00334                                 IO_Write(port,vl);
00335                         } else {
00336                                 IO_Write(port,idx);
00337                                 IO_Write(port+1u,vl);
00338                         }
00339                 }
00340                 tbl+=4;
00341         }
00342 }