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