DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #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 }