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