DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/vga_other.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 <string.h>
00021 #include <math.h>
00022 #include "dosbox.h"
00023 #include "inout.h"
00024 #include "vga.h"
00025 #include "mem.h"
00026 #include "pic.h"
00027 #include "render.h"
00028 #include "mapper.h"
00029 
00030 static void write_crtc_index_other(Bitu /*port*/,Bitu val,Bitu /*iolen*/) {
00031         vga.other.index=(Bit8u)(val & 0x1f);
00032 }
00033 
00034 static Bitu read_crtc_index_other(Bitu /*port*/,Bitu /*iolen*/) {
00035         return vga.other.index;
00036 }
00037 
00038 static void write_crtc_data_other(Bitu /*port*/,Bitu val,Bitu /*iolen*/) {
00039         switch (vga.other.index) {
00040         case 0x00:              //Horizontal total
00041                 if (vga.other.htotal ^ val) VGA_StartResize();
00042                 vga.other.htotal=(Bit8u)val;
00043                 break;
00044         case 0x01:              //Horizontal displayed chars
00045                 if (vga.other.hdend ^ val) VGA_StartResize();
00046                 vga.other.hdend=(Bit8u)val;
00047                 break;
00048         case 0x02:              //Horizontal sync position
00049                 vga.other.hsyncp=(Bit8u)val;
00050                 break;
00051         case 0x03:              //Horizontal sync width
00052                 if (machine==MCH_TANDY) vga.other.vsyncw=(Bit8u)(val >> 4);
00053                 else vga.other.vsyncw = 16; // The MC6845 has a fixed v-sync width of 16 lines
00054                 vga.other.hsyncw=(Bit8u)(val & 0xf);
00055                 break;
00056         case 0x04:              //Vertical total
00057                 if (vga.other.vtotal ^ val) VGA_StartResize();
00058                 vga.other.vtotal=(Bit8u)(val&0x7f);
00059                 break;
00060         case 0x05:              //Vertical display adjust
00061                 if (vga.other.vadjust ^ val) VGA_StartResize();
00062                 vga.other.vadjust=(Bit8u)val;
00063                 break;
00064         case 0x06:              //Vertical rows
00065                 if (vga.other.vdend ^ val) VGA_StartResize();
00066                 vga.other.vdend=(Bit8u)(val&0x7f);
00067                 break;
00068         case 0x07:              //Vertical sync position
00069                 vga.other.vsyncp=(Bit8u)val;
00070                 break;
00071         case 0x09:              //Max scanline
00072                 val &= 0x1f; // VGADOC says bit 0-3 but the MC6845 datasheet says bit 0-4
00073                 if (vga.other.max_scanline ^ val) VGA_StartResize();
00074                 vga.other.max_scanline=(Bit8u)val;
00075                 break;
00076         case 0x0A:      /* Cursor Start Register */
00077                 vga.other.cursor_start = (Bit8u)(val & 0x3f);
00078                 vga.draw.cursor.sline = (Bit8u)(val&0x1f);
00079                 vga.draw.cursor.enabled = ((val & 0x60) != 0x20);
00080                 break;
00081         case 0x0B:      /* Cursor End Register */
00082                 vga.other.cursor_end = (Bit8u)(val&0x1f);
00083                 vga.draw.cursor.eline = (Bit8u)(val&0x1f);
00084                 break;
00085         case 0x0C:      /* Start Address High Register */
00086                 // Bit 12 (depending on video mode) and 13 are actually masked too,
00087                 // but so far no need to implement it.
00088                 vga.config.display_start=(vga.config.display_start & 0x00FF) | ((val&0x3F) << 8);
00089                 break;
00090         case 0x0D:      /* Start Address Low Register */
00091                 vga.config.display_start=(vga.config.display_start & 0xFF00) | val;
00092                 break;
00093         case 0x0E:      /*Cursor Location High Register */
00094                 vga.config.cursor_start&=0x00ffu;
00095                 vga.config.cursor_start|=(unsigned int)(((Bit8u)val) << 8u);
00096                 break;
00097         case 0x0F:      /* Cursor Location Low Register */
00098                 vga.config.cursor_start&=0xff00u;
00099                 vga.config.cursor_start|=(Bit8u)val;
00100                 break;
00101         case 0x10:      /* Light Pen High */
00102                 // MC6845 datasheet says the light pen registers are only readable
00103                 vga.other.lightpen &= 0xff;
00104                 vga.other.lightpen |= (val & 0x3f)<<8;          // only 6 bits
00105                 break;
00106         case 0x11:      /* Light Pen Low */
00107                 vga.other.lightpen &= 0xff00;
00108                 vga.other.lightpen |= (Bit8u)val;
00109                 break;
00110         default:
00111                 LOG(LOG_VGAMISC,LOG_NORMAL)("MC6845:Write %X to illegal index %x",(int)val,(int)vga.other.index);
00112         }
00113 }
00114 static Bitu read_crtc_data_other(Bitu /*port*/,Bitu /*iolen*/) {
00115         switch (vga.other.index) {
00116         case 0x00:              //Horizontal total
00117                 return vga.other.htotal;
00118         case 0x01:              //Horizontal displayed chars
00119                 return vga.other.hdend;
00120         case 0x02:              //Horizontal sync position
00121                 return vga.other.hsyncp;
00122         case 0x03:              //Horizontal and vertical sync width
00123                 if (machine==MCH_TANDY)
00124                         return (unsigned int)vga.other.hsyncw | (unsigned int)(vga.other.vsyncw << 4u);
00125                 else return vga.other.hsyncw;
00126         case 0x04:              //Vertical total
00127                 return vga.other.vtotal;
00128         case 0x05:              //Vertical display adjust
00129                 return vga.other.vadjust;
00130         case 0x06:              //Vertical rows
00131                 return vga.other.vdend;
00132         case 0x07:              //Vertical sync position
00133                 return vga.other.vsyncp;
00134         case 0x09:              //Max scanline
00135                 return vga.other.max_scanline;
00136         case 0x0A:      /* Cursor Start Register */
00137                 return vga.other.cursor_start;
00138         case 0x0B:      /* Cursor End Register */
00139                 return vga.other.cursor_end;
00140         case 0x0C:      /* Start Address High Register */
00141                 return (Bit8u)(vga.config.display_start >> 8u);
00142         case 0x0D:      /* Start Address Low Register */
00143                 return (Bit8u)(vga.config.display_start & 0xffu);
00144         case 0x0E:      /*Cursor Location High Register */
00145                 return (Bit8u)(vga.config.cursor_start >> 8u);
00146         case 0x0F:      /* Cursor Location Low Register */
00147                 return (Bit8u)(vga.config.cursor_start & 0xffu);
00148         case 0x10:      /* Light Pen High */
00149                 return (Bit8u)(vga.other.lightpen >> 8u);
00150         case 0x11:      /* Light Pen Low */
00151                 return (Bit8u)(vga.other.lightpen & 0xffu);
00152         default:
00153                 LOG(LOG_VGAMISC,LOG_NORMAL)("MC6845:Read from illegal index %x",vga.other.index);
00154         }
00155         return (Bitu)(~0);
00156 }
00157 
00158 static void write_lightpen(Bitu port,Bitu val,Bitu) {
00159     (void)val;//UNUSED
00160         switch (port) {
00161         case 0x3db:     // Clear lightpen latch
00162                 vga.other.lightpen_triggered = false;
00163                 break;
00164         case 0x3dc:     // Preset lightpen latch
00165                 if (!vga.other.lightpen_triggered) {
00166                         vga.other.lightpen_triggered = true; // TODO: this shows at port 3ba/3da bit 1
00167                         
00168                         double timeInFrame = PIC_FullIndex()-vga.draw.delay.framestart;
00169                         double timeInLine = fmod(timeInFrame,vga.draw.delay.htotal);
00170                         Bitu current_scanline = (Bitu)(timeInFrame / vga.draw.delay.htotal);
00171                         
00172                         vga.other.lightpen = (Bit16u)((vga.draw.address_add/2) * (current_scanline/2));
00173                         vga.other.lightpen += (Bit16u)((timeInLine / vga.draw.delay.hdend) *
00174                                 ((float)(vga.draw.address_add/2)));
00175                 }
00176                 break;
00177         }
00178 }
00179 
00180 Bit8u cga_comp = 0;
00181 bool new_cga = 0;
00182 
00183 static double hue_offset = 0.0;
00184 
00185 static Bit8u cga16_val = 0;
00186 static void update_cga16_color(void);
00187 static Bit8u herc_pal = 0;
00188 static Bit8u mono_cga_pal = 0;
00189 static Bit8u mono_cga_bright = 0;
00190 static Bit8u const mono_cga_palettes[8][16][3] =
00191 {
00192         { // 0 - green, 4-color-optimized contrast
00193                 {0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x17,0x05},{0x01,0x1a,0x06},{0x02,0x28,0x09},{0x02,0x2c,0x0a},{0x03,0x39,0x0d},{0x03,0x3c,0x0e},
00194                 {0x00,0x07,0x01},{0x01,0x13,0x04},{0x01,0x1f,0x07},{0x01,0x23,0x08},{0x02,0x31,0x0b},{0x02,0x35,0x0c},{0x05,0x3f,0x11},{0x0d,0x3f,0x17},
00195         },
00196         { // 1 - green, 16-color-optimized contrast
00197                 {0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x15,0x05},{0x01,0x17,0x05},{0x01,0x21,0x08},{0x01,0x24,0x08},{0x02,0x2e,0x0b},{0x02,0x31,0x0b},
00198                 {0x01,0x22,0x08},{0x02,0x28,0x09},{0x02,0x30,0x0b},{0x02,0x32,0x0c},{0x03,0x39,0x0d},{0x03,0x3b,0x0e},{0x09,0x3f,0x14},{0x0d,0x3f,0x17},
00199         },
00200         { // 2 - amber, 4-color-optimized contrast
00201                 {0x00,0x00,0x00},{0x15,0x05,0x00},{0x20,0x0b,0x00},{0x24,0x0d,0x00},{0x33,0x18,0x00},{0x37,0x1b,0x00},{0x3f,0x26,0x01},{0x3f,0x2b,0x06},
00202                 {0x0b,0x02,0x00},{0x1b,0x08,0x00},{0x29,0x11,0x00},{0x2e,0x14,0x00},{0x3b,0x1e,0x00},{0x3e,0x21,0x00},{0x3f,0x32,0x0a},{0x3f,0x38,0x0d},
00203         },
00204         { // 3 - amber, 16-color-optimized contrast
00205                 {0x00,0x00,0x00},{0x15,0x05,0x00},{0x1e,0x09,0x00},{0x21,0x0b,0x00},{0x2b,0x12,0x00},{0x2f,0x15,0x00},{0x38,0x1c,0x00},{0x3b,0x1e,0x00},
00206                 {0x2c,0x13,0x00},{0x32,0x17,0x00},{0x3a,0x1e,0x00},{0x3c,0x1f,0x00},{0x3f,0x27,0x01},{0x3f,0x2a,0x04},{0x3f,0x36,0x0c},{0x3f,0x38,0x0d},
00207         },
00208         { // 4 - grey, 4-color-optimized contrast
00209                 {0x00,0x00,0x00},{0x0d,0x0d,0x0d},{0x15,0x15,0x15},{0x18,0x18,0x18},{0x24,0x24,0x24},{0x27,0x27,0x27},{0x33,0x33,0x33},{0x37,0x37,0x37},
00210                 {0x08,0x08,0x08},{0x10,0x10,0x10},{0x1c,0x1c,0x1c},{0x20,0x20,0x20},{0x2c,0x2c,0x2c},{0x2f,0x2f,0x2f},{0x3b,0x3b,0x3b},{0x3f,0x3f,0x3f},
00211         },
00212         { // 5 - grey, 16-color-optimized contrast
00213                 {0x00,0x00,0x00},{0x0d,0x0d,0x0d},{0x12,0x12,0x12},{0x15,0x15,0x15},{0x1e,0x1e,0x1e},{0x20,0x20,0x20},{0x29,0x29,0x29},{0x2c,0x2c,0x2c},
00214                 {0x1f,0x1f,0x1f},{0x23,0x23,0x23},{0x2b,0x2b,0x2b},{0x2d,0x2d,0x2d},{0x34,0x34,0x34},{0x36,0x36,0x36},{0x3d,0x3d,0x3d},{0x3f,0x3f,0x3f},
00215         },
00216         { // 6 - paper-white, 4-color-optimized contrast
00217                 {0x00,0x00,0x00},{0x0e,0x0f,0x10},{0x15,0x17,0x18},{0x18,0x1a,0x1b},{0x24,0x25,0x25},{0x27,0x28,0x28},{0x33,0x34,0x32},{0x37,0x38,0x35},
00218                 {0x09,0x0a,0x0b},{0x11,0x12,0x13},{0x1c,0x1e,0x1e},{0x20,0x22,0x22},{0x2c,0x2d,0x2c},{0x2f,0x30,0x2f},{0x3c,0x3c,0x38},{0x3f,0x3f,0x3b},
00219         },
00220         { // 7 - paper-white, 16-color-optimized contrast
00221                 {0x00,0x00,0x00},{0x0e,0x0f,0x10},{0x13,0x14,0x15},{0x15,0x17,0x18},{0x1e,0x20,0x20},{0x20,0x22,0x22},{0x29,0x2a,0x2a},{0x2c,0x2d,0x2c},
00222                 {0x1f,0x21,0x21},{0x23,0x25,0x25},{0x2b,0x2c,0x2b},{0x2d,0x2e,0x2d},{0x34,0x35,0x33},{0x37,0x37,0x34},{0x3e,0x3e,0x3a},{0x3f,0x3f,0x3b},
00223         },
00224 };
00225 
00226 static void cga16_color_select(Bit8u val) {
00227         cga16_val = val;
00228         update_cga16_color();
00229 }
00230 
00231 static void update_cga16_color(void) {
00232 // New algorithm based on code by reenigne
00233 // Works in all CGA graphics modes/color settings and can simulate older and newer CGA revisions
00234         static const double tau = 6.28318531; // == 2*pi
00235         static const double ns = 567.0/440;  // degrees of hue shift per nanosecond
00236 
00237         double tv_brightness = 0.0; // hardcoded for simpler implementation
00238         double tv_saturation = (new_cga ? 0.7 : 0.6);
00239 
00240         bool bw = (vga.tandy.mode_control&4) != 0;
00241         bool color_sel = (cga16_val&0x20) != 0;
00242         bool background_i = (cga16_val&0x10) != 0;      // Really foreground intensity, but this is what the CGA schematic calls it.
00243         bool bpp1 = (vga.tandy.mode_control&0x10) != 0;
00244         Bit8u overscan = cga16_val&0x0f;  // aka foreground colour in 1bpp mode
00245 
00246         double chroma_coefficient = new_cga ? 0.29 : 0.72;
00247         double b_coefficient = new_cga ? 0.07 : 0;
00248         double g_coefficient = new_cga ? 0.22 : 0;
00249         double r_coefficient = new_cga ? 0.1 : 0;
00250         double i_coefficient = new_cga ? 0.32 : 0.28;
00251         double rgbi_coefficients[0x10];
00252         for (int c = 0; c < 0x10; c++) {
00253                 double v = 0;
00254                 if ((c & 1) != 0)
00255                         v += b_coefficient;
00256                 if ((c & 2) != 0)
00257                         v += g_coefficient;
00258                 if ((c & 4) != 0)
00259                         v += r_coefficient;
00260                 if ((c & 8) != 0)
00261                         v += i_coefficient;
00262                 rgbi_coefficients[c] = v;
00263         }
00264 
00265         // The pixel clock delay calculation is not accurate for 2bpp, but the difference is small and a more accurate calculation would be too slow.
00266         static const double rgbi_pixel_delay = 15.5*ns;
00267         static const double chroma_pixel_delays[8] = {
00268                 0,        // Black:   no chroma
00269                 35*ns,    // Blue:    no XORs
00270                 44.5*ns,  // Green:   XOR on rising and falling edges
00271                 39.5*ns,  // Cyan:    XOR on falling but not rising edge
00272                 44.5*ns,  // Red:     XOR on rising and falling edges
00273                 39.5*ns,  // Magenta: XOR on falling but not rising edge
00274                 44.5*ns,  // Yellow:  XOR on rising and falling edges
00275                 39.5*ns}; // White:   XOR on falling but not rising edge
00276         double pixel_clock_delay;
00277         int o = overscan == 0 ? 15 : overscan;
00278         if (overscan == 8)
00279                 pixel_clock_delay = rgbi_pixel_delay;
00280         else {
00281                 double d = rgbi_coefficients[o];
00282                 pixel_clock_delay = (chroma_pixel_delays[o & 7]*chroma_coefficient + rgbi_pixel_delay*d)/(chroma_coefficient + d);
00283         }
00284         pixel_clock_delay -= 21.5*ns;  // correct for delay of color burst
00285 
00286         double hue_adjust = (-(90-33)-hue_offset+pixel_clock_delay)*tau/360.0;
00287         double chroma_signals[8][4];
00288         for (Bit8u i=0; i<4; i++) {
00289                 chroma_signals[0][i] = 0;
00290                 chroma_signals[7][i] = 1;
00291                 for (Bit8u j=0; j<6; j++) {
00292                         static const double phases[6] = {
00293                                 270 - 21.5*ns,  // blue
00294                                 135 - 29.5*ns,  // green
00295                                 180 - 21.5*ns,  // cyan
00296                                   0 - 21.5*ns,  // red
00297                                 315 - 29.5*ns,  // magenta
00298                                  90 - 21.5*ns}; // yellow/burst
00299                         // All the duty cycle fractions are the same, just under 0.5 as the rising edge is delayed 2ns more than the falling edge.
00300                         static const double duty = 0.5 - 2*ns/360.0;
00301 
00302                         // We have a rectangle wave with period 1 (in units of the reciprocal of the color burst frequency) and duty
00303                         // cycle fraction "duty" and phase "phase". We band-limit this wave to frequency 2 and sample it at intervals of 1/4.
00304                         // We model our band-limited wave with 4 frequency components:
00305                         //   f(x) = a + b*sin(x*tau) + c*cos(x*tau) + d*sin(x*2*tau)
00306                         // Then:
00307                         //   a =   integral(0, 1, f(x)*dx) = duty
00308                         //   b = 2*integral(0, 1, f(x)*sin(x*tau)*dx) = 2*integral(0, duty, sin(x*tau)*dx) = 2*(1-cos(x*tau))/tau
00309                         //   c = 2*integral(0, 1, f(x)*cos(x*tau)*dx) = 2*integral(0, duty, cos(x*tau)*dx) = 2*sin(duty*tau)/tau
00310                         //   d = 2*integral(0, 1, f(x)*sin(x*2*tau)*dx) = 2*integral(0, duty, sin(x*4*pi)*dx) = 2*(1-cos(2*tau*duty))/(2*tau)
00311                         double a = duty;
00312                         double b = 2.0*(1.0-cos(duty*tau))/tau;
00313                         double c = 2.0*sin(duty*tau)/tau;
00314                         double d = 2.0*(1.0-cos(duty*2*tau))/(2*tau);
00315 
00316                         double x = (phases[j] + 21.5*ns + pixel_clock_delay)/360.0 + i/4.0;
00317 
00318                         chroma_signals[j+1][i] = a + b*sin(x*tau) + c*cos(x*tau) + d*sin(x*2*tau);
00319                 }
00320         }
00321         Bitu CGApal[4] = {
00322                 overscan,
00323                 (Bitu)(2 + (color_sel||bw ? 1 : 0) + (background_i ? 8 : 0)),
00324                 (Bitu)(4 + (color_sel&&!bw? 1 : 0) + (background_i ? 8 : 0)),
00325                 (Bitu)(6 + (color_sel||bw ? 1 : 0) + (background_i ? 8 : 0))
00326         };
00327         for (Bit8u x=0; x<4; x++) {      // Position of pixel in question
00328                 bool even = (x & 1) == 0;
00329                 for (Bit8u bits=0; bits<(even ? 0x10 : 0x40); ++bits) {
00330                         double Y=0, I=0, Q=0;
00331                         for (Bit8u p=0; p<4; p++) {  // Position within color carrier cycle
00332                                 // generate pixel pattern.
00333                                 Bit8u rgbi;
00334                                 if (bpp1)
00335                                         rgbi = ((bits >> (3-p)) & (even ? 1 : 2)) != 0 ? overscan : 0;
00336                                 else
00337                                         if (even)
00338                                                 rgbi = CGApal[(bits >> (2-(p&2)))&3];
00339                                         else
00340                                                 rgbi = CGApal[(bits >> (4-((p+1)&6)))&3];
00341                                 Bit8u c = rgbi & 7;
00342                                 if (bw && c != 0)
00343                                         c = 7;
00344 
00345                                 // calculate composite output
00346                                 double chroma = chroma_signals[c][(p+x)&3]*chroma_coefficient;
00347                                 double composite = chroma + rgbi_coefficients[rgbi];
00348 
00349                                 Y+=composite;
00350                                 if (!bw) { // burst on
00351                                         I+=composite*2*cos(hue_adjust + (p+x)*tau/4.0);
00352                                         Q+=composite*2*sin(hue_adjust + (p+x)*tau/4.0);
00353                                 }
00354                         }
00355 
00356                         double contrast = 1 - tv_brightness;
00357 
00358                         Y = (contrast*Y/4.0) + tv_brightness; if (Y>1.0) Y=1.0; if (Y<0.0) Y=0.0;
00359                         I = (contrast*I/4.0) * tv_saturation; if (I>0.5957) I=0.5957; if (I<-0.5957) I=-0.5957;
00360                         Q = (contrast*Q/4.0) * tv_saturation; if (Q>0.5226) Q=0.5226; if (Q<-0.5226) Q=-0.5226;
00361 
00362                         static const double gamma = 2.2;
00363 
00364                         double R = Y + 0.9563*I + 0.6210*Q;     R = (R - 0.075) / (1-0.075); if (R<0) R=0; if (R>1) R=1;
00365                         double G = Y - 0.2721*I - 0.6474*Q;     G = (G - 0.075) / (1-0.075); if (G<0) G=0; if (G>1) G=1;
00366                         double B = Y - 1.1069*I + 1.7046*Q;     B = (B - 0.075) / (1-0.075); if (B<0) B=0; if (B>1) B=1;
00367                         R = pow(R, gamma);
00368                         G = pow(G, gamma);
00369                         B = pow(B, gamma);
00370 
00371                         int r = static_cast<int>(255*pow( 1.5073*R -0.3725*G -0.0832*B, 1/gamma)); if (r<0) r=0; if (r>255) r=255;
00372                         int g = static_cast<int>(255*pow(-0.0275*R +0.9350*G +0.0670*B, 1/gamma)); if (g<0) g=0; if (g>255) g=255;
00373                         int b = static_cast<int>(255*pow(-0.0272*R -0.0401*G +1.1677*B, 1/gamma)); if (b<0) b=0; if (b>255) b=255;
00374 
00375                         Bit8u index = bits | ((x & 1) == 0 ? 0x30 : 0x80) | ((x & 2) == 0 ? 0x40 : 0);
00376                         RENDER_SetPal(index,r,g,b);
00377                 }
00378         }
00379 }
00380 
00381 static void IncreaseHue(bool pressed) {
00382         if (!pressed)
00383                 return;
00384         hue_offset += 5.0;
00385         update_cga16_color();
00386         LOG_MSG("Hue at %f",hue_offset); 
00387 }
00388 
00389 static void DecreaseHue(bool pressed) {
00390         if (!pressed)
00391                 return;
00392         hue_offset -= 5.0;
00393         update_cga16_color();
00394         LOG_MSG("Hue at %f",hue_offset); 
00395 }
00396 
00397 static void write_cga_color_select(Bitu val) {
00398         vga.tandy.color_select=val;
00399         switch(vga.mode) {
00400         case  M_TANDY4: {
00401                 Bit8u base = (val & 0x10) ? 0x08 : 0;
00402                 Bit8u bg = val & 0xf;
00403                 if (vga.tandy.mode_control & 0x4)       // cyan red white
00404                         VGA_SetCGA4Table(bg, 3+base, 4+base, 7+base);
00405                 else if (val & 0x20)                            // cyan magenta white
00406                         VGA_SetCGA4Table(bg, 3+base, 5+base, 7+base);
00407                 else                                                            // green red brown
00408                         VGA_SetCGA4Table(bg, 2+base, 4+base, 6+base);
00409                 vga.tandy.border_color = bg;
00410                 vga.attr.overscan_color = bg;
00411                 break;
00412         }
00413         case M_TANDY2:
00414                 VGA_SetCGA2Table(0,val & 0xf);
00415                 vga.attr.overscan_color = 0;
00416                 break;
00417         case M_CGA16:
00418                 cga16_color_select(val);
00419                 break;
00420         case M_TEXT:
00421                 vga.tandy.border_color = val & 0xf;
00422                 vga.attr.overscan_color = 0;
00423                 break;
00424         case M_AMSTRAD: // Amstrad "palette". 0x3D9
00425                 break;
00426         default:
00427                 break;
00428         }
00429 }
00430 
00431 static void write_cga(Bitu port,Bitu val,Bitu /*iolen*/) {
00432         switch (port) {
00433         case 0x3d8:
00434                 vga.tandy.mode_control=(Bit8u)val;
00435                 vga.attr.disabled = (val&0x8)? 0: 1; 
00436                 if (vga.tandy.mode_control & 0x2) {             // graphics mode
00437                         if (vga.tandy.mode_control & 0x10) {// highres mode
00438                                 if (machine == MCH_AMSTRAD) {
00439                                         VGA_SetMode(M_AMSTRAD);                 //Amstrad 640x200x16 video mode.
00440                                 } else if ((cga_comp==1 || (cga_comp==0 && !(val&0x4))) && !mono_cga) { // composite display
00441                                         VGA_SetMode(M_CGA16);           // composite ntsc 640x200 16 color mode
00442                                 } else {
00443                                         VGA_SetMode(M_TANDY2);
00444                                 }
00445                         } else {                                                        // lowres mode
00446                                 if (cga_comp==1) {                              // composite display
00447                                         VGA_SetMode(M_CGA16);           // composite ntsc 640x200 16 color mode
00448                                 } else {
00449                                         VGA_SetMode(M_TANDY4);
00450                                 }
00451                         }
00452 
00453                         write_cga_color_select(vga.tandy.color_select);
00454                 } else {
00455                         VGA_SetMode(M_TANDY_TEXT);
00456                 }
00457                 VGA_SetBlinking(val & 0x20);
00458                 break;
00459         case 0x3d9: // color select
00460                 write_cga_color_select(val);
00461                 if( machine==MCH_AMSTRAD ) {
00462                         vga.amstrad.mask_plane = ( val | ( val << 8 ) | ( val << 16 ) | ( val << 24 ) ) & 0x0F0F0F0F;
00463                 }
00464                 break;
00465         case 0x3dd:
00466                 vga.amstrad.write_plane = val & 0x0F;
00467                 break;
00468         case 0x3de:
00469                 vga.amstrad.read_plane = val & 0x03;
00470                 break;
00471         case 0x3df:
00472                 vga.amstrad.border_color = val & 0x0F;
00473                 break;
00474         }
00475 }
00476 
00477 static void CGAModel(bool pressed) {
00478         if (!pressed) return;
00479         new_cga = !new_cga;
00480         update_cga16_color();
00481         LOG_MSG("%s model CGA selected", new_cga ? "Late" : "Early");
00482 }
00483  
00484 static void Composite(bool pressed) {
00485         if (!pressed) return;
00486         if (++cga_comp>2) cga_comp=0;
00487         LOG_MSG("Composite output: %s",(cga_comp==0)?"auto":((cga_comp==1)?"on":"off"));
00488         // switch RGB and Composite if in graphics mode
00489         if (vga.tandy.mode_control & 0x2)
00490                 write_cga(0x3d8,vga.tandy.mode_control,1);
00491 }
00492 
00493 static void tandy_update_palette() {
00494         // TODO mask off bits if needed
00495         if (machine == MCH_TANDY) {
00496                 switch (vga.mode) {
00497                 case M_TANDY2:
00498                         VGA_SetCGA2Table(vga.attr.palette[0],
00499                                 vga.attr.palette[vga.tandy.color_select&0xf]);
00500                         break;
00501                 case M_TANDY4:
00502                         if (vga.tandy.gfx_control & 0x8) {
00503                                 // 4-color high resolution - might be an idea to introduce M_TANDY4H
00504                                 VGA_SetCGA4Table( // function sets both medium and highres 4color tables
00505                                         vga.attr.palette[0], vga.attr.palette[1],
00506                                         vga.attr.palette[2], vga.attr.palette[3]);
00507                         } else {
00508                                 Bit8u color_set = 0;
00509                                 Bit8u r_mask = 0xf;
00510                                 if (vga.tandy.color_select & 0x10) color_set |= 8; // intensity
00511                                 if (vga.tandy.color_select & 0x20) color_set |= 1; // Cyan Mag. White
00512                                 if (vga.tandy.mode_control & 0x04) {                    // Cyan Red White
00513                                         color_set |= 1; 
00514                                         r_mask &= ~1;
00515                                 }
00516                                 VGA_SetCGA4Table(
00517                                         vga.attr.palette[vga.tandy.color_select&0xf],
00518                                         vga.attr.palette[(2|color_set)& vga.tandy.palette_mask],
00519                                         vga.attr.palette[(4|(color_set& r_mask))& vga.tandy.palette_mask],
00520                                         vga.attr.palette[(6|color_set)& vga.tandy.palette_mask]);
00521                         }
00522                         break;
00523                 default:
00524                         break;
00525                 }
00526         } else {
00527                 // PCJr
00528                 switch (vga.mode) {
00529                 case M_TANDY2:
00530                         VGA_SetCGA2Table(vga.attr.palette[0],vga.attr.palette[1]);
00531                         break;
00532                 case M_TANDY4:
00533                         VGA_SetCGA4Table(
00534                                 vga.attr.palette[0], vga.attr.palette[1],
00535                                 vga.attr.palette[2], vga.attr.palette[3]);
00536                         break;
00537                 default:
00538                         break;
00539                 }
00540         }
00541 }
00542 
00543 void VGA_SetModeNow(VGAModes mode);
00544 
00545 static void TANDY_FindMode(void) {
00546         if (vga.tandy.mode_control & 0x2) {
00547                 if (vga.tandy.gfx_control & 0x10) {
00548                         if (vga.mode==M_TANDY4) {
00549                                 VGA_SetModeNow(M_TANDY16);
00550                         } else VGA_SetMode(M_TANDY16);
00551                 }
00552                 else if (vga.tandy.gfx_control & 0x08) {
00553                         VGA_SetMode(M_TANDY4);
00554                 }
00555                 else if (vga.tandy.mode_control & 0x10)
00556                         VGA_SetMode(M_TANDY2);
00557                 else {
00558                         if (vga.mode==M_TANDY16) {
00559                                 VGA_SetModeNow(M_TANDY4);
00560                         } else VGA_SetMode(M_TANDY4);
00561                 }
00562                 tandy_update_palette();
00563         } else {
00564                 VGA_SetMode(M_TANDY_TEXT);
00565         }
00566 }
00567 
00568 static void PCJr_FindMode(void) {
00569         if (vga.tandy.mode_control & 0x2) {
00570                 if (vga.tandy.mode_control & 0x10) {
00571                         /* bit4 of mode control 1 signals 16 colour graphics mode */
00572                         if (vga.mode==M_TANDY4) VGA_SetModeNow(M_TANDY16); // TODO lowres mode only
00573                         else VGA_SetMode(M_TANDY16);
00574                 } else if (vga.tandy.gfx_control & 0x08) {
00575                         /* bit3 of mode control 2 signals 2 colour graphics mode */
00576                         VGA_SetMode(M_TANDY2);
00577                 } else {
00578                         /* otherwise some 4-colour graphics mode */
00579                         if (vga.mode==M_TANDY16) VGA_SetModeNow(M_TANDY4);
00580                         else VGA_SetMode(M_TANDY4);
00581                 }
00582                 tandy_update_palette();
00583         } else {
00584                 VGA_SetMode(M_TANDY_TEXT);
00585         }
00586 }
00587 
00588 static void TandyCheckLineMask(void ) {
00589         if ( vga.tandy.extended_ram & 1 ) {
00590                 vga.tandy.line_mask = 0;
00591         } else if ( vga.tandy.mode_control & 0x2) {
00592                 vga.tandy.line_mask |= 1;
00593         }
00594         if ( vga.tandy.line_mask ) {
00595                 vga.tandy.line_shift = 13;
00596                 vga.tandy.addr_mask = (1 << 13) - 1;
00597         } else {
00598                 vga.tandy.addr_mask = (Bitu)(~0);
00599                 vga.tandy.line_shift = 0;
00600         }
00601 }
00602 
00603 static void write_tandy_reg(Bit8u val) {
00604         switch (vga.tandy.reg_index) {
00605         case 0x0:
00606                 if (machine==MCH_PCJR) {
00607                         vga.tandy.mode_control=val;
00608                         VGA_SetBlinking(val & 0x20);
00609                         PCJr_FindMode();
00610                         if (val&0x8) vga.attr.disabled &= ~1;
00611                         else vga.attr.disabled |= 1;
00612                 } else {
00613                         LOG(LOG_VGAMISC,LOG_NORMAL)("Unhandled Write %2X to tandy reg %X",val,vga.tandy.reg_index);
00614                 }
00615                 break;
00616         case 0x1:       /* Palette mask */
00617                 vga.tandy.palette_mask = val;
00618                 tandy_update_palette();
00619                 break;
00620         case 0x2:       /* Border color */
00621                 vga.tandy.border_color=val;
00622                 break;
00623         case 0x3:       /* More control */
00624                 vga.tandy.gfx_control=val;
00625                 if (machine==MCH_TANDY) TANDY_FindMode();
00626                 else PCJr_FindMode();
00627                 break;
00628         case 0x5:       /* Extended ram page register */
00629                 // Bit 0 enables extended ram
00630                 // Bit 7 Switches clock, 0 -> cga 28.6 , 1 -> mono 32.5
00631                 vga.tandy.extended_ram = val;
00632                 //This is a bit of a hack to enable mapping video memory differently for highres mode
00633                 TandyCheckLineMask();
00634                 VGA_SetupHandlers();
00635                 break;
00636         default:
00637                 if ((vga.tandy.reg_index & 0xf0) == 0x10) { // color palette
00638                         vga.attr.palette[vga.tandy.reg_index-0x10] = val&0xf;
00639                         tandy_update_palette();
00640                 } else
00641                         LOG(LOG_VGAMISC,LOG_NORMAL)("Unhandled Write %2X to tandy reg %X",val,vga.tandy.reg_index);
00642         }
00643 }
00644 
00645 static void write_tandy(Bitu port,Bitu val,Bitu /*iolen*/) {
00646         switch (port) {
00647         case 0x3d8:
00648                 val &= 0x3f; // only bits 0-6 are used
00649                 if (vga.tandy.mode_control ^ val) {
00650                         vga.tandy.mode_control=(Bit8u)val;
00651                         if (val&0x8) vga.attr.disabled &= ~1;
00652                         else vga.attr.disabled |= 1;
00653                         TandyCheckLineMask();
00654                         VGA_SetBlinking(val & 0x20);
00655                         TANDY_FindMode();
00656                         VGA_StartResize();
00657                 }
00658                 break;
00659         case 0x3d9:
00660                 vga.tandy.color_select=val;
00661                 tandy_update_palette();
00662                 break;
00663         case 0x3da:
00664                 vga.tandy.reg_index=(Bit8u)val;
00665                 //if (val&0x10) vga.attr.disabled |= 2;
00666                 //else vga.attr.disabled &= ~2;
00667                 break;
00668 //      case 0x3dd:     //Extended ram page address register:
00669 //              break;
00670         case 0x3de:
00671                 write_tandy_reg((Bit8u)val);
00672                 break;
00673         case 0x3df:
00674                 // CRT/processor page register
00675                 // See the comments on the PCJr version of this register.
00676                 // A difference to it is:
00677                 // Bit 3-5: Processor page CPU_PG
00678                 // The remapped range is 32kB instead of 16. Therefore CPU_PG bit 0
00679                 // appears to be ORed with CPU A14 (to preserve some sort of
00680                 // backwards compatibility?), resulting in odd pages being mapped
00681                 // as 2x16kB. Implemeted in vga_memory.cpp Tandy handler.
00682 
00683                 vga.tandy.line_mask = (Bit8u)(val >> 6);
00684                 vga.tandy.draw_bank = val & ((vga.tandy.line_mask&2) ? 0x6 : 0x7);
00685                 vga.tandy.mem_bank = (val >> 3) & 7;
00686                 TandyCheckLineMask();
00687                 VGA_SetupHandlers();
00688                 break;
00689         }
00690 }
00691 
00692 static void write_pcjr(Bitu port,Bitu val,Bitu /*iolen*/) {
00693         switch (port) {
00694         case 0x3da:
00695                 if (vga.tandy.pcjr_flipflop) write_tandy_reg((Bit8u)val);
00696                 else {
00697                         vga.tandy.reg_index=(Bit8u)val;
00698                         if (vga.tandy.reg_index & 0x10)
00699                                 vga.attr.disabled |= 2;
00700                         else vga.attr.disabled &= ~2;
00701                 }
00702                 vga.tandy.pcjr_flipflop=!vga.tandy.pcjr_flipflop;
00703                 break;
00704         case 0x3df:
00705                 // CRT/processor page register
00706                 
00707                 // Bit 0-2: CRT page PG0-2
00708                 // In one- and two bank modes, bit 0-2 select the 16kB memory
00709                 // area of system RAM that is displayed on the screen.
00710                 // In 4-banked modes, bit 1-2 select the 32kB memory area.
00711                 // Bit 2 only has effect when the PCJR upgrade to 128k is installed.
00712                 
00713                 // Bit 3-5: Processor page CPU_PG
00714                 // Selects the 16kB area of system RAM that is mapped to
00715                 // the B8000h IBM PC video memory window. Since A14-A16 of the 
00716                 // processor are unconditionally replaced with these bits when
00717                 // B8000h is accessed, the 16kB area is mapped to the 32kB
00718                 // range twice in a row. (Scuba Venture writes across the boundary)
00719                 
00720                 // Bit 6-7: Video Address mode
00721                 // 0: CRTC addresses A0-12 directly, accessing 8k characters
00722                 //    (+8k attributes). Used in text modes (one bank).
00723                 //    PG0-2 in effect. 16k range.
00724                 // 1: CRTC A12 is replaced with CRTC RA0 (see max_scanline).
00725                 //    This results in the even/odd scanline two bank system.
00726                 //    PG0-2 in effect. 16k range.
00727                 // 2: Documented as unused. CRTC addresses A0-12, PG0 is replaced
00728                 //    with RA1. Looks like nonsense.
00729                 //    PG1-2 in effect. 32k range which cannot be used completely.
00730                 // 3: CRTC A12 is replaced with CRTC RA0, PG0 is replaced with
00731                 //    CRTC RA1. This results in the 4-bank mode.
00732                 //    PG1-2 in effect. 32k range.
00733 
00734                 vga.tandy.line_mask = (Bit8u)(val >> 6);
00735                 vga.tandy.draw_bank = val & ((vga.tandy.line_mask&2) ? 0x6 : 0x7);
00736                 vga.tandy.mem_bank = (val >> 3) & 7;
00737                 vga.tandy.draw_base = &MemBase[vga.tandy.draw_bank * 16 * 1024];
00738                 vga.tandy.mem_base = &MemBase[vga.tandy.mem_bank * 16 * 1024];
00739                 TandyCheckLineMask();
00740                 VGA_SetupHandlers();
00741                 break;
00742         }
00743 }
00744 
00745 static void CycleHercPal(bool pressed) {
00746         if (!pressed) return;
00747         if (++herc_pal>3) herc_pal=0;
00748         Herc_Palette();
00749 }
00750 
00751 static void CycleMonoCGAPal(bool pressed) {
00752         if (!pressed) return;
00753         if (++mono_cga_pal>3) mono_cga_pal=0;
00754         Mono_CGA_Palette();
00755 }
00756 
00757 static void CycleMonoCGABright(bool pressed) {
00758         if (!pressed) return;
00759         if (++mono_cga_bright>1) mono_cga_bright=0;
00760         Mono_CGA_Palette();
00761 }
00762         
00763 void Herc_Palette(void) {       
00764         switch (herc_pal) {
00765         case 0: // White
00766                 VGA_DAC_SetEntry(0x7,0x2a,0x2a,0x2a);
00767                 VGA_DAC_SetEntry(0xf,0x3f,0x3f,0x3f);
00768                 break;
00769         case 1: // Amber
00770                 VGA_DAC_SetEntry(0x7,0x34,0x20,0x00);
00771                 VGA_DAC_SetEntry(0xf,0x3f,0x34,0x00);
00772                 break;
00773         case 2: // Paper-white
00774                 VGA_DAC_SetEntry(0x7,0x2c,0x2d,0x2c);
00775                 VGA_DAC_SetEntry(0xf,0x3f,0x3f,0x3b);
00776                 break;
00777         case 3: // Green
00778                 VGA_DAC_SetEntry(0x7,0x00,0x26,0x00);
00779                 VGA_DAC_SetEntry(0xf,0x00,0x3f,0x00);
00780                 break;
00781         }
00782         VGA_DAC_CombineColor(1,0x7);
00783         VGA_DAC_CombineColor(2,0xf);
00784 }
00785 
00786 static void HercBlend(bool pressed) {
00787         if (!pressed) return;
00788         vga.herc.blend = !vga.herc.blend;
00789         VGA_SetupDrawing(0);
00790 }
00791 
00792 void Mono_CGA_Palette(void) {   
00793         for (Bit8u ct=0;ct<16;ct++) {
00794                 VGA_DAC_SetEntry(ct,
00795                                                  mono_cga_palettes[2*mono_cga_pal+mono_cga_bright][ct][0],
00796                                                  mono_cga_palettes[2*mono_cga_pal+mono_cga_bright][ct][1],
00797                                                  mono_cga_palettes[2*mono_cga_pal+mono_cga_bright][ct][2]
00798                 );
00799                 VGA_DAC_CombineColor(ct,ct);
00800         }
00801 }
00802 
00803 static void write_hercules(Bitu port,Bitu val,Bitu /*iolen*/) {
00804         switch (port) {
00805         case 0x3b8: {
00806                 // the protected bits can always be cleared but only be set if the 
00807                 // protection bits are set
00808                 if (vga.herc.mode_control&0x2) {
00809                         // already set
00810                         if (!(val&0x2)) {
00811                                 vga.herc.mode_control &= ~0x2;
00812                                 VGA_SetMode(M_HERC_TEXT);
00813                         }
00814                 } else {
00815                         // not set, can only set if protection bit is set
00816                         if ((val & 0x2) && (vga.herc.enable_bits & 0x1)) {
00817                                 vga.herc.mode_control |= 0x2;
00818                                 VGA_SetMode(M_HERC_GFX);
00819                         }
00820                 }
00821                 if (vga.herc.mode_control&0x80) {
00822                         if (!(val&0x80)) {
00823                                 vga.herc.mode_control &= ~0x80;
00824                                 vga.tandy.draw_base = &vga.mem.linear[0];
00825                         }
00826                 } else {
00827                         if ((val & 0x80) && (vga.herc.enable_bits & 0x2)) {
00828                                 vga.herc.mode_control |= 0x80;
00829                                 vga.tandy.draw_base = &vga.mem.linear[32*1024];
00830                         }
00831                 }
00832                 vga.draw.blinking = (val&0x20)!=0;
00833                 vga.herc.mode_control &= 0x82;
00834                 vga.herc.mode_control |= val & ~0x82u;
00835                 break;
00836                 }
00837         case 0x3bf:
00838                 if ( vga.herc.enable_bits ^ val) {
00839                         vga.herc.enable_bits=val;
00840                         // Bit 1 enables the upper 32k of video memory,
00841                         // so update the handlers
00842                         VGA_SetupHandlers();
00843                 }
00844                 break;
00845         }
00846 }
00847 
00848 /* static Bitu read_hercules(Bitu port,Bitu iolen) {
00849         LOG_MSG("read from Herc port %x",port);
00850         return 0;
00851 } */
00852 
00853 Bitu read_herc_status(Bitu /*port*/,Bitu /*iolen*/) {
00854         // 3BAh (R):  Status Register
00855         // bit   0  Horizontal sync
00856         //       1  Light pen status (only some cards)
00857         //       3  Video signal
00858         //     4-6      000: Hercules
00859         //                      001: Hercules Plus
00860         //                      101: Hercules InColor
00861         //                      111: Unknown clone
00862         //       7  Vertical sync inverted
00863 
00864         double timeInFrame = PIC_FullIndex()-vga.draw.delay.framestart;
00865         Bit8u retval=0x72; // Hercules ident; from a working card (Winbond W86855AF)
00866                                         // Another known working card has 0x76 ("KeysoGood", full-length)
00867         if (timeInFrame < vga.draw.delay.vrstart ||
00868                 timeInFrame > vga.draw.delay.vrend) retval |= 0x80;
00869 
00870         double timeInLine=fmod(timeInFrame,vga.draw.delay.htotal);
00871         if (timeInLine >= vga.draw.delay.hrstart &&
00872                 timeInLine <= vga.draw.delay.hrend) retval |= 0x1;
00873 
00874         // 688 Attack sub checks bit 3 - as a workaround have the bit enabled
00875         // if no sync active (corresponds to a completely white screen)
00876         if ((retval&0x81)==0x80) retval |= 0x8;
00877         return retval;
00878 }
00879 
00880 
00881 void VGA_SetupOther(void) {
00882         Bitu i;
00883         memset( &vga.tandy, 0, sizeof( vga.tandy ));
00884         vga.attr.disabled = 0;
00885         vga.config.bytes_skip=0;
00886 
00887         //Initialize values common for most machines, can be overwritten
00888         vga.tandy.draw_base = vga.mem.linear;
00889         vga.tandy.mem_base = vga.mem.linear;
00890         vga.tandy.addr_mask = 8*1024 - 1;
00891         vga.tandy.line_mask = 3;
00892         vga.tandy.line_shift = 13;
00893 
00894         if (machine==MCH_CGA || machine==MCH_AMSTRAD || IS_TANDY_ARCH) {
00895                 extern Bit8u int10_font_08[256 * 8];
00896                 for (i=0;i<256;i++)     memcpy(&vga.draw.font[i*32],&int10_font_08[i*8],8);
00897                 vga.draw.font_tables[0]=vga.draw.font_tables[1]=vga.draw.font;
00898         }
00899         if (machine==MCH_CGA || IS_TANDY_ARCH || machine==MCH_HERC) {
00900                 IO_RegisterWriteHandler(0x3db,write_lightpen,IO_MB);
00901                 IO_RegisterWriteHandler(0x3dc,write_lightpen,IO_MB);
00902         }
00903         if (machine==MCH_HERC) {
00904                 extern Bit8u int10_font_14[256 * 14];
00905                 for (i=0;i<256;i++)     memcpy(&vga.draw.font[i*32],&int10_font_14[i*14],14);
00906                 vga.draw.font_tables[0]=vga.draw.font_tables[1]=vga.draw.font;
00907                 MAPPER_AddHandler(HercBlend,MK_nothing,0,"hercblend","Herc Blend");
00908                 MAPPER_AddHandler(CycleHercPal,MK_nothing,0,"hercpal","Herc Pal");
00909         }
00910         if (machine==MCH_CGA || machine==MCH_AMSTRAD) {
00911                 vga.amstrad.mask_plane = 0x07070707;
00912                 vga.amstrad.write_plane = 0x0F;
00913                 vga.amstrad.read_plane = 0x00;
00914                 vga.amstrad.border_color = 0x00;
00915 
00916                 IO_RegisterWriteHandler(0x3d8,write_cga,IO_MB);
00917                 IO_RegisterWriteHandler(0x3d9,write_cga,IO_MB);
00918 
00919                 if( machine==MCH_AMSTRAD )
00920                 {
00921                         IO_RegisterWriteHandler(0x3dd,write_cga,IO_MB);
00922                         IO_RegisterWriteHandler(0x3de,write_cga,IO_MB);
00923                         IO_RegisterWriteHandler(0x3df,write_cga,IO_MB);
00924                 }
00925 
00926                 if(!mono_cga) {
00927             MAPPER_AddHandler(IncreaseHue,MK_nothing,0,"inchue","Inc Hue");
00928             MAPPER_AddHandler(DecreaseHue,MK_nothing,0,"dechue","Dec Hue");
00929             MAPPER_AddHandler(CGAModel,MK_nothing,0,"cgamodel","CGA Model");
00930             MAPPER_AddHandler(Composite,MK_nothing,0,"cgacomp","CGA Comp");
00931         } else {
00932             MAPPER_AddHandler(CycleMonoCGAPal,MK_nothing,0,"monocgapal","Mono CGA Pal"); 
00933             MAPPER_AddHandler(CycleMonoCGABright,MK_nothing,0,"monocgabright","Mono CGA Bright"); 
00934         }
00935         }
00936         if (machine==MCH_TANDY) {
00937                 write_tandy( 0x3df, 0x0, 0 );
00938                 IO_RegisterWriteHandler(0x3d8,write_tandy,IO_MB);
00939                 IO_RegisterWriteHandler(0x3d9,write_tandy,IO_MB);
00940                 IO_RegisterWriteHandler(0x3da,write_tandy,IO_MB);
00941                 IO_RegisterWriteHandler(0x3de,write_tandy,IO_MB);
00942                 IO_RegisterWriteHandler(0x3df,write_tandy,IO_MB);
00943         }
00944         if (machine==MCH_PCJR) {
00945                 //write_pcjr will setup base address
00946                 write_pcjr( 0x3df, 0x7 | (0x7 << 3), 0 );
00947                 IO_RegisterWriteHandler(0x3da,write_pcjr,IO_MB);
00948                 IO_RegisterWriteHandler(0x3df,write_pcjr,IO_MB);
00949                 // additional CRTC access documented
00950                 IO_RegisterWriteHandler(0x3d0,write_crtc_index_other,IO_MB);
00951                 IO_RegisterWriteHandler(0x3d1,write_crtc_data_other,IO_MB);
00952         }
00953         if (machine==MCH_HERC) {
00954                 Bitu base=0x3b0;
00955                 for (Bitu i = 0; i < 4; i++) {
00956                         // The registers are repeated as the address is not decoded properly;
00957                         // The official ports are 3b4, 3b5
00958                         IO_RegisterWriteHandler(base+i*2,write_crtc_index_other,IO_MB);
00959                         IO_RegisterWriteHandler(base+i*2+1,write_crtc_data_other,IO_MB);
00960                         IO_RegisterReadHandler(base+i*2,read_crtc_index_other,IO_MB);
00961                         IO_RegisterReadHandler(base+i*2+1,read_crtc_data_other,IO_MB);
00962                 }
00963                 vga.herc.blend=false;
00964                 vga.herc.enable_bits=0;
00965                 vga.herc.mode_control=0xa; // first mode written will be text mode
00966                 vga.crtc.underline_location = 13;
00967                 IO_RegisterWriteHandler(0x3b8,write_hercules,IO_MB);
00968                 IO_RegisterWriteHandler(0x3bf,write_hercules,IO_MB);
00969                 IO_RegisterReadHandler(0x3ba,read_herc_status,IO_MB);
00970         }
00971         if (machine==MCH_CGA) {
00972                 Bitu base=0x3d0;
00973                 for (Bitu port_ct=0; port_ct<4; port_ct++) {
00974                         IO_RegisterWriteHandler(base+port_ct*2,write_crtc_index_other,IO_MB);
00975                         IO_RegisterWriteHandler(base+port_ct*2+1,write_crtc_data_other,IO_MB);
00976                         IO_RegisterReadHandler(base+port_ct*2,read_crtc_index_other,IO_MB);
00977                         IO_RegisterReadHandler(base+port_ct*2+1,read_crtc_data_other,IO_MB);
00978                 }
00979         }
00980         if (IS_TANDY_ARCH) {
00981                 Bitu base=0x3d4;
00982                 IO_RegisterWriteHandler(base,write_crtc_index_other,IO_MB);
00983                 IO_RegisterWriteHandler(base+1,write_crtc_data_other,IO_MB);
00984                 IO_RegisterReadHandler(base,read_crtc_index_other,IO_MB);
00985                 IO_RegisterReadHandler(base+1,read_crtc_data_other,IO_MB);
00986         }
00987         if (machine==MCH_AMSTRAD) {
00988                 Bitu base=machine==MCH_HERC ? 0x3b4 : 0x3d4;
00989                 IO_RegisterWriteHandler(base,write_crtc_index_other,IO_MB);
00990                 IO_RegisterWriteHandler(base+1,write_crtc_data_other,IO_MB);
00991                 IO_RegisterReadHandler(base,read_crtc_index_other,IO_MB);
00992                 IO_RegisterReadHandler(base+1,read_crtc_data_other,IO_MB);
00993 
00994                 // Check for CGA CRTC port mirroring (Prohibition).
00995                 if( base==0x3d4 ) {
00996                         base=0x3d0;
00997                         IO_RegisterWriteHandler(base,write_crtc_index_other,IO_MB);
00998                         IO_RegisterWriteHandler(base+1,write_crtc_data_other,IO_MB);
00999                         IO_RegisterReadHandler(base,read_crtc_index_other,IO_MB);
01000                         IO_RegisterReadHandler(base+1,read_crtc_data_other,IO_MB);
01001                 }
01002         }
01003         // AMSTRAD
01004 }
01005