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 <stdlib.h> 00021 #include "dosbox.h" 00022 #include "inout.h" 00023 #include "vga.h" 00024 #include "debug.h" 00025 #include "cpu.h" 00026 #include "video.h" 00027 #include "pic.h" 00028 00029 #define crtc(blah) vga.crtc.blah 00030 00031 00032 void VGA_MapMMIO(void); 00033 void VGA_UnmapMMIO(void); 00034 void page_flip_debug_notify(); 00035 00036 void VGA_CheckAddrShift() { 00037 //Byte,word,dword mode 00038 if ( IS_VGA_ARCH && crtc(underline_location) & 0x40 ) 00039 vga.config.addr_shift = 2u; 00040 else if ( IS_EGAVGA_ARCH && crtc( mode_control) & 0x40 ) 00041 vga.config.addr_shift = 0u; 00042 else 00043 vga.config.addr_shift = 1u; 00044 } 00045 00046 void vga_write_p3d5(Bitu port,Bitu val,Bitu iolen); 00047 Bitu DEBUG_EnableDebugger(void); 00048 00049 extern bool vga_ignore_hdispend_change_if_smaller; 00050 00051 void vga_write_p3d4(Bitu port,Bitu val,Bitu iolen) { 00052 (void)iolen;//UNUSED 00053 (void)port;//UNUSED 00054 crtc(index)=(Bit8u)val; 00055 } 00056 00057 void vga_pc98_direct_cursor_pos(Bit16u address) { 00058 vga.config.cursor_start = address; 00059 } 00060 00061 Bitu vga_read_p3d4(Bitu port,Bitu iolen) { 00062 (void)port;//UNUSED 00063 (void)iolen;//UNUSED 00064 00065 /* NOTES: Paradise/Westdern Digital SVGA decodes only bits [5:0] inclusive and repeat every 0x40 */ 00066 00067 return crtc(index); 00068 } 00069 00070 void vga_write_p3d5(Bitu port,Bitu val,Bitu iolen) { 00071 (void)port;//UNUSED 00072 // if((crtc(index)!=0xe)&&(crtc(index)!=0xf)) 00073 // LOG_MSG("CRTC w #%2x val %2x",crtc(index),val); 00074 switch(crtc(index)) { 00075 case 0x00: /* Horizontal Total Register */ 00076 if (crtc(read_only)) break; 00077 crtc(horizontal_total)=(Bit8u)val; 00078 /* 0-7 Horizontal Total Character Clocks-5 */ 00079 break; 00080 case 0x01: /* Horizontal Display End Register */ 00081 if (crtc(read_only)) break; 00082 if (val != crtc(horizontal_display_end)) { 00083 /* we permit a configuration option that if set, means do NOT call VGA_StartResize() 00084 * if the new value is less than the current value, to protect against rapid changes 00085 * from demos like DoWhackaDo. */ 00086 if (vga_ignore_hdispend_change_if_smaller && val < crtc(horizontal_display_end)) { 00087 /* do not call VGA_StartResize, allow change */ 00088 crtc(horizontal_display_end)=(Bit8u)val; 00089 LOG_MSG("VGA Horz. Display End: accepting change but will not call VGA_StartResize()"); 00090 } 00091 else { 00092 crtc(horizontal_display_end)=(Bit8u)val; 00093 VGA_StartResize(); 00094 } 00095 } 00096 /* 0-7 Number of Character Clocks Displayed -1 */ 00097 break; 00098 case 0x02: /* Start Horizontal Blanking Register */ 00099 if (crtc(read_only)) break; 00100 crtc(start_horizontal_blanking)=(Bit8u)val; 00101 /* 0-7 The count at which Horizontal Blanking starts */ 00102 break; 00103 case 0x03: /* End Horizontal Blanking Register */ 00104 if (crtc(read_only)) break; 00105 crtc(end_horizontal_blanking)=(Bit8u)val; 00106 /* 00107 0-4 Horizontal Blanking ends when the last 6 bits of the character 00108 counter equals this field. Bit 5 is at 3d4h index 5 bit 7. 00109 5-6 Number of character clocks to delay start of display after Horizontal 00110 Total has been reached. 00111 7 Access to Vertical Retrace registers if set. If clear reads to 3d4h 00112 index 10h and 11h access the Lightpen read back registers ?? 00113 */ 00114 break; 00115 case 0x04: /* Start Horizontal Retrace Register */ 00116 if (crtc(read_only)) break; 00117 crtc(start_horizontal_retrace)=(Bit8u)val; 00118 /* 0-7 Horizontal Retrace starts when the Character Counter reaches this value. */ 00119 break; 00120 case 0x05: /* End Horizontal Retrace Register */ 00121 if (crtc(read_only)) break; 00122 crtc(end_horizontal_retrace)=(Bit8u)val; 00123 /* 00124 0-4 Horizontal Retrace ends when the last 5 bits of the character counter 00125 equals this value. 00126 5-6 Number of character clocks to delay start of display after Horizontal 00127 Retrace. 00128 7 bit 5 of the End Horizontal Blanking count (See 3d4h index 3 bit 0-4) 00129 */ 00130 break; 00131 case 0x06: /* Vertical Total Register */ 00132 if (crtc(read_only)) break; 00133 if (val != crtc(vertical_total)) { 00134 crtc(vertical_total)=(Bit8u)val; 00135 VGA_StartResize(); 00136 } 00137 /* 0-7 Lower 8 bits of the Vertical Total. Bit 8 is found in 3d4h index 7 00138 bit 0. Bit 9 is found in 3d4h index 7 bit 5. 00139 Note: For the VGA this value is the number of scan lines in the display -2. 00140 */ 00141 break; 00142 case 0x07: /* Overflow Register */ 00143 //Line compare bit ignores read only */ 00144 vga.config.line_compare=(vga.config.line_compare & 0x6ff) | (val & 0x10) << 4; 00145 if (crtc(read_only)) break; 00146 if ((vga.crtc.overflow ^ val) & 0xd6) { 00147 crtc(overflow)=(Bit8u)val; 00148 VGA_StartResize(); 00149 } else crtc(overflow)=(Bit8u)val; 00150 /* 00151 0 Bit 8 of Vertical Total (3d4h index 6) 00152 1 Bit 8 of Vertical Display End (3d4h index 12h) 00153 2 Bit 8 of Vertical Retrace Start (3d4h index 10h) 00154 3 Bit 8 of Start Vertical Blanking (3d4h index 15h) 00155 4 Bit 8 of Line Compare Register (3d4h index 18h) 00156 5 Bit 9 of Vertical Total (3d4h index 6) 00157 6 Bit 9 of Vertical Display End (3d4h index 12h) 00158 7 Bit 9 of Vertical Retrace Start (3d4h index 10h) 00159 */ 00160 break; 00161 case 0x08: /* Preset Row Scan Register */ 00162 crtc(preset_row_scan)=(Bit8u)val; 00163 vga.config.hlines_skip=val&31; 00164 if (IS_VGA_ARCH) vga.config.bytes_skip=(val>>5)&3; 00165 else vga.config.bytes_skip=0; 00166 // LOG_DEBUG("Skip lines %d bytes %d",vga.config.hlines_skip,vga.config.bytes_skip); 00167 /* 00168 0-4 Number of lines we have scrolled down in the first character row. 00169 Provides Smooth Vertical Scrolling.b 00170 5-6 Number of bytes to skip at the start of scanline. Provides Smooth 00171 Horizontal Scrolling together with the Horizontal Panning Register 00172 (3C0h index 13h). 00173 */ 00174 break; 00175 case 0x09: /* Maximum Scan Line Register */ 00176 { 00177 if (IS_VGA_ARCH) { 00178 vga.config.line_compare &= 0x5ff; 00179 vga.config.line_compare |= (val&0x40)<<3; 00180 } else if(machine==MCH_EGA) { 00181 val &= 0x7f; // EGA ignores the doublescan bit 00182 } 00183 Bit8u old = crtc(maximum_scan_line); 00184 crtc(maximum_scan_line) = (Bit8u)val; 00185 00186 unsigned char chk = 0x20; 00187 00188 if (!vga.draw.doublescan_set) 00189 chk |= 0x81; /* doublescan + LSB of maximum scanline */ 00190 00191 if ((old ^ val) & chk) VGA_StartResize(); 00192 vga.draw.address_line_total = (val & 0x1F) + 1; 00193 if (val&0x80) vga.draw.address_line_total *= 2; 00194 /* 00195 0-4 Number of scan lines in a character row -1. In graphics modes this is 00196 the number of times (-1) the line is displayed before passing on to 00197 the next line (0: normal, 1: double, 2: triple...). 00198 This is independent of bit 7, except in CGA modes which seems to 00199 require this field to be 1 and bit 7 to be set to work. 00200 5 Bit 9 of Start Vertical Blanking 00201 6 Bit 9 of Line Compare Register 00202 7 Doubles each scan line if set. I.e. displays 200 lines on a 400 display. 00203 */ 00204 break; 00205 } 00206 case 0x0A: /* Cursor Start Register */ 00207 crtc(cursor_start)=(Bit8u)val; 00208 vga.draw.cursor.sline=val&0x1f; 00209 if (IS_VGA_ARCH) vga.draw.cursor.enabled=!(val&0x20); 00210 else vga.draw.cursor.enabled=true; 00211 /* 00212 0-4 First scanline of cursor within character. 00213 5 Turns Cursor off if set 00214 */ 00215 break; 00216 case 0x0B: /* Cursor End Register */ 00217 crtc(cursor_end)=(Bit8u)val; 00218 vga.draw.cursor.eline=val&0x1f; 00219 vga.draw.cursor.delay=(val>>5)&0x3; 00220 00221 /* 00222 0-4 Last scanline of cursor within character 00223 5-6 Delay of cursor data in character clocks. 00224 */ 00225 break; 00226 case 0x0C: /* Start Address High Register */ 00227 crtc(start_address_high)=(Bit8u)val; 00228 vga.config.display_start=(vga.config.display_start & 0xFF00FF)| (val << 8); 00229 /* 0-7 Upper 8 bits of the start address of the display buffer */ 00230 page_flip_debug_notify(); 00231 break; 00232 case 0x0D: /* Start Address Low Register */ 00233 crtc(start_address_low)=(Bit8u)val; 00234 vga.config.display_start=(vga.config.display_start & 0xFFFF00)| val; 00235 /* 0-7 Lower 8 bits of the start address of the display buffer */ 00236 page_flip_debug_notify(); 00237 break; 00238 case 0x0E: /*Cursor Location High Register */ 00239 crtc(cursor_location_high)=(Bit8u)val; 00240 vga.config.cursor_start&=0xff00ff; 00241 vga.config.cursor_start|=val << 8; 00242 /* 0-7 Upper 8 bits of the address of the cursor */ 00243 break; 00244 case 0x0F: /* Cursor Location Low Register */ 00245 //TODO update cursor on screen 00246 crtc(cursor_location_low)=(Bit8u)val; 00247 vga.config.cursor_start&=0xffff00; 00248 vga.config.cursor_start|=val; 00249 /* 0-7 Lower 8 bits of the address of the cursor */ 00250 break; 00251 case 0x10: /* Vertical Retrace Start Register */ 00252 crtc(vertical_retrace_start)=(Bit8u)val; 00253 /* 00254 0-7 Lower 8 bits of Vertical Retrace Start. Vertical Retrace starts when 00255 the line counter reaches this value. Bit 8 is found in 3d4h index 7 00256 bit 2. Bit 9 is found in 3d4h index 7 bit 7. 00257 */ 00258 break; 00259 case 0x11: /* Vertical Retrace End Register */ 00260 crtc(vertical_retrace_end)=(Bit8u)val; 00261 00262 if (IS_EGAVGA_ARCH && !(val & 0x10)) { 00263 vga.draw.vret_triggered=false; 00264 if (GCC_UNLIKELY(machine==MCH_EGA)) PIC_DeActivateIRQ(9); 00265 } 00266 if (IS_VGA_ARCH) crtc(read_only)=(val & 128)>0; 00267 else crtc(read_only)=false; 00268 /* 00269 0-3 Vertical Retrace ends when the last 4 bits of the line counter equals 00270 this value. 00271 4 if clear Clears pending Vertical Interrupts. 00272 5 Vertical Interrupts (IRQ 2) disabled if set. Can usually be left 00273 disabled, but some systems (including PS/2) require it to be enabled. 00274 6 If set selects 5 refresh cycles per scanline rather than 3. 00275 7 Disables writing to registers 0-7 if set 3d4h index 7 bit 4 is not 00276 affected by this bit. 00277 */ 00278 break; 00279 case 0x12: /* Vertical Display End Register */ 00280 if (val!=crtc(vertical_display_end)) { 00281 if (abs(static_cast<int>((Bits)val-(Bits)crtc(vertical_display_end)))<3) { 00282 // delay small vde changes a bit to avoid screen resizing 00283 // if they are reverted in a short timeframe 00284 PIC_RemoveEvents(VGA_SetupDrawing); 00285 vga.draw.resizing=false; 00286 crtc(vertical_display_end)=(Bit8u)val; 00287 VGA_StartResize(150); 00288 } else { 00289 crtc(vertical_display_end)=(Bit8u)val; 00290 VGA_StartResize(); 00291 } 00292 } 00293 /* 00294 0-7 Lower 8 bits of Vertical Display End. The display ends when the line 00295 counter reaches this value. Bit 8 is found in 3d4h index 7 bit 1. 00296 Bit 9 is found in 3d4h index 7 bit 6. 00297 */ 00298 break; 00299 case 0x13: /* Offset register */ 00300 crtc(offset)=(Bit8u)val; 00301 vga.config.scan_len&=0x300; 00302 vga.config.scan_len|=val; 00303 VGA_CheckScanLength(); 00304 /* 00305 0-7 Number of bytes in a scanline / K. Where K is 2 for byte mode, 4 for 00306 word mode and 8 for Double Word mode. 00307 */ 00308 break; 00309 case 0x14: /* Underline Location Register */ 00310 crtc(underline_location)=(Bit8u)val; 00311 VGA_CheckAddrShift(); 00312 VGA_CheckScanLength(); 00313 /* 00314 0-4 Position of underline within Character cell. 00315 5 If set memory address is only changed every fourth character clock. 00316 6 Double Word mode addressing if set 00317 */ 00318 break; 00319 case 0x15: /* Start Vertical Blank Register */ 00320 if (val!=crtc(start_vertical_blanking)) { 00321 crtc(start_vertical_blanking)=(Bit8u)val; 00322 VGA_StartResize(); 00323 } 00324 /* 00325 0-7 Lower 8 bits of Vertical Blank Start. Vertical blanking starts when 00326 the line counter reaches this value. Bit 8 is found in 3d4h index 7 00327 bit 3. 00328 */ 00329 break; 00330 case 0x16: /* End Vertical Blank Register */ 00331 if (val!=crtc(end_vertical_blanking)) { 00332 crtc(end_vertical_blanking)=(Bit8u)val; 00333 VGA_StartResize(); 00334 } 00335 /* 00336 0-6 Vertical blanking stops when the lower 7 bits of the line counter 00337 equals this field. Some SVGA chips uses all 8 bits! 00338 IBM actually says bits 0-7. 00339 */ 00340 break; 00341 case 0x17: /* Mode Control Register */ 00342 crtc(mode_control)=(Bit8u)val; 00343 vga.tandy.line_mask = (~val) & 3u; 00344 00345 if ( vga.tandy.line_mask ) { 00346 vga.tandy.line_shift = 13u; 00347 vga.tandy.addr_mask = (1u << 13u) - 1u; 00348 } else { 00349 vga.tandy.addr_mask = ~0u; 00350 vga.tandy.line_shift = 0; 00351 } 00352 00353 VGA_CheckAddrShift(); 00354 VGA_CheckScanLength(); 00355 00356 //Should we really need to do a determinemode here? 00357 // VGA_DetermineMode(); 00358 /* 00359 0 If clear use CGA compatible memory addressing system 00360 by substituting character row scan counter bit 0 for address bit 13, 00361 thus creating 2 banks for even and odd scan lines. 00362 1 If clear use Hercules compatible memory addressing system by 00363 substituting character row scan counter bit 1 for address bit 14, 00364 thus creating 4 banks. 00365 2 If set increase scan line counter only every second line. 00366 3 If set increase memory address counter only every other character clock. 00367 5 When in Word Mode bit 15 is rotated to bit 0 if this bit is set else 00368 bit 13 is rotated into bit 0. 00369 6 If clear system is in word mode. Addresses are rotated 1 position up 00370 bringing either bit 13 or 15 into bit 0. 00371 7 Clearing this bit will reset the display system until the bit is set again. 00372 */ 00373 break; 00374 case 0x18: /* Line Compare Register */ 00375 crtc(line_compare)=(Bit8u)val; 00376 vga.config.line_compare=(vga.config.line_compare & 0x700) | val; 00377 /* 00378 0-7 Lower 8 bits of the Line Compare. When the Line counter reaches this 00379 value, the display address wraps to 0. Provides Split Screen 00380 facilities. Bit 8 is found in 3d4h index 7 bit 4. 00381 Bit 9 is found in 3d4h index 9 bit 6. 00382 */ 00383 break; 00384 default: 00385 if (svga.write_p3d5) { 00386 svga.write_p3d5(crtc(index), val, iolen); 00387 } else { 00388 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:CRTC:Write to unknown index %X",crtc(index)); 00389 } 00390 break; 00391 } 00392 } 00393 00394 00395 Bitu vga_read_p3d5x(Bitu port,Bitu iolen); 00396 Bitu vga_read_p3d5(Bitu port,Bitu iolen) { 00397 Bitu retval = vga_read_p3d5x(port,iolen); 00398 // LOG_MSG("CRTC r #%2x val %2x",crtc(index),retval); 00399 return retval; 00400 } 00401 00402 Bitu vga_read_p3d5x(Bitu port,Bitu iolen) { 00403 (void)iolen;//UNUSED 00404 (void)port;//UNUSED 00405 switch(crtc(index)) { 00406 case 0x00: /* Horizontal Total Register */ 00407 return crtc(horizontal_total); 00408 case 0x01: /* Horizontal Display End Register */ 00409 return crtc(horizontal_display_end); 00410 case 0x02: /* Start Horizontal Blanking Register */ 00411 return crtc(start_horizontal_blanking); 00412 case 0x03: /* End Horizontal Blanking Register */ 00413 return crtc(end_horizontal_blanking); 00414 case 0x04: /* Start Horizontal Retrace Register */ 00415 return crtc(start_horizontal_retrace); 00416 case 0x05: /* End Horizontal Retrace Register */ 00417 return crtc(end_horizontal_retrace); 00418 case 0x06: /* Vertical Total Register */ 00419 return crtc(vertical_total); 00420 case 0x07: /* Overflow Register */ 00421 return crtc(overflow); 00422 case 0x08: /* Preset Row Scan Register */ 00423 return crtc(preset_row_scan); 00424 case 0x09: /* Maximum Scan Line Register */ 00425 return crtc(maximum_scan_line); 00426 case 0x0A: /* Cursor Start Register */ 00427 return crtc(cursor_start); 00428 case 0x0B: /* Cursor End Register */ 00429 return crtc(cursor_end); 00430 case 0x0C: /* Start Address High Register */ 00431 return crtc(start_address_high); 00432 case 0x0D: /* Start Address Low Register */ 00433 return crtc(start_address_low); 00434 case 0x0E: /*Cursor Location High Register */ 00435 return crtc(cursor_location_high); 00436 case 0x0F: /* Cursor Location Low Register */ 00437 return crtc(cursor_location_low); 00438 case 0x10: /* Vertical Retrace Start Register */ 00439 return crtc(vertical_retrace_start); 00440 case 0x11: /* Vertical Retrace End Register */ 00441 return crtc(vertical_retrace_end); 00442 case 0x12: /* Vertical Display End Register */ 00443 return crtc(vertical_display_end); 00444 case 0x13: /* Offset register */ 00445 return crtc(offset); 00446 case 0x14: /* Underline Location Register */ 00447 return crtc(underline_location); 00448 case 0x15: /* Start Vertical Blank Register */ 00449 return crtc(start_vertical_blanking); 00450 case 0x16: /* End Vertical Blank Register */ 00451 return crtc(end_vertical_blanking); 00452 case 0x17: /* Mode Control Register */ 00453 return crtc(mode_control); 00454 case 0x18: /* Line Compare Register */ 00455 return crtc(line_compare); 00456 default: 00457 if (svga.read_p3d5) { 00458 return svga.read_p3d5(crtc(index), iolen); 00459 } else { 00460 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:CRTC:Read from unknown index %X",crtc(index)); 00461 return 0x0; 00462 } 00463 } 00464 } 00465 00466 // save state support 00467 void POD_Save_VGA_Crtc( std::ostream& stream ) 00468 { 00469 // - pure struct data 00470 WRITE_POD( &vga.crtc, vga.crtc ); 00471 00472 00473 // no static globals found 00474 } 00475 00476 00477 void POD_Load_VGA_Crtc( std::istream& stream ) 00478 { 00479 // - pure struct data 00480 READ_POD( &vga.crtc, vga.crtc ); 00481 00482 00483 // no static globals found 00484 }