DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/vga_pc98_egc.cpp
00001 /*
00002  *  Copyright (C) 2018  Jon Campbell
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 #include "dosbox.h"
00020 #include "setup.h"
00021 #include "video.h"
00022 #include "pic.h"
00023 #include "vga.h"
00024 #include "inout.h"
00025 #include "programs.h"
00026 #include "support.h"
00027 #include "setup.h"
00028 #include "timer.h"
00029 #include "mem.h"
00030 #include "util_units.h"
00031 #include "control.h"
00032 #include "pc98_cg.h"
00033 #include "pc98_dac.h"
00034 #include "pc98_gdc.h"
00035 #include "pc98_gdc_const.h"
00036 #include "mixer.h"
00037 
00038 #include <string.h>
00039 #include <stdlib.h>
00040 #include <string>
00041 #include <stdio.h>
00042 
00043 #if defined(_MSC_VER)
00044 #pragma warning(disable:4065) /* switch statements without case labels */
00045 #endif
00046 
00047 void pc98_egc_shift_reinit();
00048 
00049 extern egc_quad             pc98_egc_bgcm;
00050 extern egc_quad             pc98_egc_fgcm;
00051 
00052 uint8_t                     pc98_egc_access=0;
00053 uint8_t                     pc98_egc_srcmask[2]; /* host given (Neko: egc.srcmask) */
00054 uint8_t                     pc98_egc_maskef[2]; /* effective (Neko: egc.mask2) */
00055 uint8_t                     pc98_egc_mask[2]; /* host given (Neko: egc.mask) */
00056 
00057 uint8_t                     pc98_egc_fgc = 0;
00058 uint8_t                     pc98_egc_lead_plane = 0;
00059 uint8_t                     pc98_egc_compare_lead = 0;
00060 uint8_t                     pc98_egc_lightsource = 0;
00061 uint8_t                     pc98_egc_shiftinput = 0;
00062 uint8_t                     pc98_egc_regload = 0;
00063 uint8_t                     pc98_egc_rop = 0xF0;
00064 uint8_t                     pc98_egc_foreground_color = 0;
00065 uint8_t                     pc98_egc_background_color = 0;
00066 
00067 bool                        pc98_egc_shift_descend = false;
00068 uint8_t                     pc98_egc_shift_destbit = 0;
00069 uint8_t                     pc98_egc_shift_srcbit = 0;
00070 uint16_t                    pc98_egc_shift_length = 0xF;
00071 
00072 Bitu pc98_egc4a0_read(Bitu port,Bitu iolen) {
00073     (void)iolen;//UNUSED
00074     /* Neko Project II suggests the I/O ports disappear when not in EGC mode.
00075      * Is that true? */
00076     if (!(pc98_gdc_vramop & (1 << VOPBIT_EGC))) {
00077 //        LOG_MSG("EGC 4A0 read port 0x%x when EGC not enabled",(unsigned int)port);
00078         return ~0ul;
00079     }
00080 
00081     /* assume: (port & 1) == 0 [even] and iolen == 2 */
00082     switch (port & 0x0E) {
00083         default:
00084             LOG_MSG("PC-98 EGC: Unhandled read from 0x%x",(unsigned int)port);
00085             break;
00086     };
00087 
00088     return ~0ul;
00089 }
00090 
00091 void pc98_egc4a0_write(Bitu port,Bitu val,Bitu iolen) {
00092     (void)iolen;//UNUSED
00093     /* Neko Project II suggests the I/O ports disappear when not in EGC mode.
00094      * Is that true? */
00095     if (!(pc98_gdc_vramop & (1 << VOPBIT_EGC))) {
00096 //        LOG_MSG("EGC 4A0 write port 0x%x when EGC not enabled",(unsigned int)port);
00097         return;
00098     }
00099 
00100     /* assume: (port & 1) == 0 [even] and iolen == 2 */
00101     switch (port & 0x0E) {
00102         case 0x0: /* 0x4A0 */
00103             /* bits [15:8] = 0xFF
00104              * bits [7:0] = enable writing to plane (NTS: only bits 3-0 have meaning in 16-color mode).
00105              * as far as I can tell, bits [7:0] correspond to the same enable bits as port 0x7C [3:0] */
00106             pc98_egc_access = val & 0xFF;
00107             break;
00108         case 0x2: /* 0x4A2 */
00109             /* bits [15:15] = 0
00110              * bits [14:13] = foreground, background color
00111              *    11 = invalid
00112              *    10 = foreground color
00113              *    01 = background color
00114              *    00 = pattern register
00115              * bits [12:12] = 0
00116              * bits [11:8] = lead plane
00117              *    0111 = VRAM plane #7
00118              *    0110 = VRAM plane #6
00119              *    0101 = VRAM plane #5
00120              *    0100 = VRAM plane #4
00121              *    0011 = VRAM plane #3
00122              *    0010 = VRAM plane #2
00123              *    0001 = VRAM plane #1
00124              *    0000 = VRAM plane #0
00125              * bits [7:0] = unused (0xFF) */
00126             pc98_egc_fgc = (val >> 13) & 3;
00127             pc98_egc_lead_plane = (val >> 8) & 15;
00128             break;
00129         case 0x4: /* 0x4A4 */
00130             /* bits [15:14] = 0 (unused)
00131              * bits [13:13] = 0=compare lead plane  1=don't
00132              * bits [12:11] = light source
00133              *    11 = invalid
00134              *    10 = write the contents of the palette register
00135              *    01 = write the result of the raster operation
00136              *    00 = write CPU data
00137              * bits [10:10] = read source
00138              *    1 = shifter input is CPU write data
00139              *    0 = shifter input is VRAM data
00140              * bits [9:8] = register load
00141              *    11 = invalid
00142              *    10 = load VRAM data before writing on VRAM write
00143              *    01 = load VRAM data into pattern/tile register on VRAM read
00144              *    00 = Do not change pattern/tile register
00145              * bits [7:0] = ROP
00146              *    shifter:       11110000
00147              *    destination:   11001100
00148              *    pattern reg:   10101010
00149              *
00150              *    examples:
00151              *    11110000 = VRAM transfer
00152              *    00001111 = VRAM reverse transfer
00153              *    11001100 = NOP
00154              *    00110011 = VRAM inversion
00155              *    11111111 = VRAM fill
00156              *    00000000 = VRAM erase
00157              *    10101010 = Pattern fill
00158              *    01010101 = Pattern reversal fill */
00159             pc98_egc_compare_lead = ((val >> 13) & 1) ^ 1;
00160             pc98_egc_lightsource = (val >> 11) & 3;
00161             pc98_egc_shiftinput = (val >> 10) & 1;
00162             pc98_egc_regload = (val >> 8) & 3;
00163             pc98_egc_rop = (val & 0xFF);
00164             break;
00165         case 0x6: /* 0x4A6 */
00166             /* If FGC = 0 and BGC = 0:
00167              *   bits [15:0] = 0
00168              * If FGC = 1 or BGC = 1:
00169              *   bits [15:8] = 0
00170              *   bits [7:0] = foreground color (all 8 bits used in 256-color mode) */
00171             pc98_egc_foreground_color = val;
00172             pc98_egc_fgcm[0].w = (val & 1) ? 0xFFFF : 0x0000;
00173             pc98_egc_fgcm[1].w = (val & 2) ? 0xFFFF : 0x0000;
00174             pc98_egc_fgcm[2].w = (val & 4) ? 0xFFFF : 0x0000;
00175             pc98_egc_fgcm[3].w = (val & 8) ? 0xFFFF : 0x0000;
00176             break;
00177         case 0x8: /* 0x4A8 */
00178             if (pc98_egc_compare_lead == 0)
00179                 *((uint16_t*)pc98_egc_mask) = val;
00180             break;
00181         case 0xA: /* 0x4AA */
00182             /* If FGC = 0 and BGC = 0:
00183              *   bits [15:0] = 0
00184              * If FGC = 1 or BGC = 1:
00185              *   bits [15:8] = 0
00186              *   bits [7:0] = foreground color (all 8 bits used in 256-color mode) */
00187             pc98_egc_background_color = val;
00188             pc98_egc_bgcm[0].w = (val & 1) ? 0xFFFF : 0x0000;
00189             pc98_egc_bgcm[1].w = (val & 2) ? 0xFFFF : 0x0000;
00190             pc98_egc_bgcm[2].w = (val & 4) ? 0xFFFF : 0x0000;
00191             pc98_egc_bgcm[3].w = (val & 8) ? 0xFFFF : 0x0000;
00192             break;
00193         case 0xC: /* 0x4AC */
00194             /* bits[15:13] = 0
00195              * bits[12:12] = shift direction 0=ascend 1=descend
00196              * bits[11:8] = 0
00197              * bits[7:4] = destination bit address
00198              * bits[3:0] = source bit address */
00199             pc98_egc_shift_descend = !!((val >> 12) & 1);
00200             pc98_egc_shift_destbit = (val >> 4) & 0xF;
00201             pc98_egc_shift_srcbit = val & 0xF;
00202             pc98_egc_shift_reinit();
00203             break;
00204         case 0xE: /* 0x4AE */
00205             /* bits[15:12] = 0
00206              * bits[11:0] = bit length (0 to 4095) */
00207             pc98_egc_shift_length = val & 0xFFF;
00208             pc98_egc_shift_reinit();
00209             break;
00210         default:
00211             // LOG_MSG("PC-98 EGC: Unhandled write to 0x%x val 0x%x",(unsigned int)port,(unsigned int)val);
00212             break;
00213     };
00214 }
00215 
00216 // I/O access to 0x4A0-0x4AF must be WORD sized and even port, or the system hangs if you try.
00217 Bitu pc98_egc4a0_read_warning(Bitu port,Bitu iolen) {
00218     /* Neko Project II suggests the I/O ports disappear when not in EGC mode.
00219      * Is that true? */
00220     if (!(pc98_gdc_vramop & (1 << VOPBIT_EGC))) {
00221 //        LOG_MSG("EGC 4A0 read port 0x%x when EGC not enabled",(unsigned int)port);
00222         return ~0ul;
00223     }
00224 
00225     LOG_MSG("PC-98 EGC warning: I/O read from port 0x%x (len=%u) known to possibly hang the system on real hardware",
00226         (unsigned int)port,(unsigned int)iolen);
00227 
00228     return ~0ul;
00229 }
00230 
00231 // I/O access to 0x4A0-0x4AF must be WORD sized and even port, or the system hangs if you try.
00232 void pc98_egc4a0_write_warning(Bitu port,Bitu val,Bitu iolen) {
00233     /* Neko Project II suggests the I/O ports disappear when not in EGC mode.
00234      * Is that true? */
00235     if (!(pc98_gdc_vramop & (1 << VOPBIT_EGC))) {
00236 //        LOG_MSG("EGC 4A0 write port 0x%x when EGC not enabled",(unsigned int)port);
00237         return;
00238     }
00239 
00240     switch (port & 0xF) {
00241         case 0x6:
00242             /* if the BIOS reports EGC, many early games will write bytewise I/O to port 4A6h */
00243             pc98_egc_foreground_color = val;
00244             pc98_egc_fgcm[0].w = (val & 1) ? 0xFFFF : 0x0000;
00245             pc98_egc_fgcm[1].w = (val & 2) ? 0xFFFF : 0x0000;
00246             pc98_egc_fgcm[2].w = (val & 4) ? 0xFFFF : 0x0000;
00247             pc98_egc_fgcm[3].w = (val & 8) ? 0xFFFF : 0x0000;
00248             break;
00249         default:
00250             LOG_MSG("PC-98 EGC warning: I/O write to port 0x%x (val=0x%x len=%u) known to possibly hang the system on real hardware",
00251                 (unsigned int)port,(unsigned int)val,(unsigned int)iolen);
00252             break;
00253     }
00254 }
00255