DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/vga_crtc.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 <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 }