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