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