DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/vga_pc98_cg.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 /* Character Generator (CG) font access state */
00044 uint16_t                    a1_font_load_addr = 0;
00045 uint8_t                     a1_font_char_offset = 0;
00046 
00047 /* Character Generator ports.
00048  * This is in fact officially documented by NEC in
00049  * a 1986 book published about NEC BIOS and BASIC ROM. */
00050 Bitu pc98_a1_read(Bitu port,Bitu iolen) {
00051     (void)iolen;//UNUSED
00052     switch (port) {
00053         case 0xA9: // an 8-bit I/O port to access font RAM by...
00054             // NOTES: On a PC-9821 Lt2 laptop, the character ROM doesn't seem to latch valid data beyond
00055             //        0xxx5D. Often this reads back as zero, but depending on whatever random data is floating
00056             //        on the bus can read back nonzero. This doesn't apply to 0x0000-0x00FF of course (single wide
00057             //        characters), but only to the double-wide character set where (c & 0x007F) >= 0x5D.
00058             //        This behavior should be emulated. */
00059             return pc98_font_char_read(a1_font_load_addr,a1_font_char_offset & 0xF,(a1_font_char_offset & 0x20) ? 0 : 1);
00060         default:
00061             break;
00062     }
00063 
00064     return ~0ul;
00065 }
00066 
00067 /* Character Generator ports.
00068  * This is in fact officially documented by NEC in
00069  * a 1986 book published about NEC BIOS and BASIC ROM. */
00070 void pc98_a1_write(Bitu port,Bitu val,Bitu iolen) {
00071     (void)iolen;//UNUSED
00072     switch (port) {
00073         /* A3,A1 (out only) two JIS bytes that make up the char code */
00074         case 0xA1:
00075             a1_font_load_addr &= 0x00FF;
00076             a1_font_load_addr |= (val & 0xFF) << 8;
00077             break;
00078         case 0xA3:
00079             a1_font_load_addr &= 0xFF00;
00080             a1_font_load_addr |= (val & 0xFF);
00081             break;
00082         case 0xA5:
00083             /* From documentation:
00084              *
00085              *    bit [7:6] = Dont care
00086              *    bit [5]   = L/R
00087              *    bit [4]   = 0
00088              *    bit [3:0] = C3-C0
00089              *
00090              * This so far is consistent with real hardware behavior */
00091             a1_font_char_offset = (uint8_t)val;
00092             break;
00093         case 0xA7:
00094             /* TODO: Various controls for the text layer */
00095             break;
00096         case 0xA9: // an 8-bit I/O port to access font RAM by...
00097                    // this is what Touhou Project uses to load fonts.
00098                    // never mind decompiling INT 18h on real hardware shows instead
00099                    // a similar sequence with REP MOVSW to A400:0000...
00100                    //
00101                    // there's a restriction noted with INT 18h AH=1Ah where the only
00102                    // codes you can overwrite are 0xxx76 and 0xxx77. I'm guessing that
00103                    // having 512KB of RAM out there dedicated to nothing but fonts
00104                    // is probably not economical to NEC's bottom line, and this
00105                    // restriction makes me wonder if the font is held in ROM except
00106                    // for this narrow sliver of codes, which map to about 8KB of RAM
00107                    // (128*2*16) * 2 = 8192 bytes
00108                    //
00109                    // I'm also guessing that this RAM is not involved with the single-wide
00110                    // character set, which is why writes to 0x0056/0x0057 are redirected to
00111                    // 0x8056/0x8057. Without this hack, Touhou Project 2 will overwrite
00112                    // the letter 'W' when loading it's font data (Level 1 will show "Eastern  ind"
00113                    // instead of "Eastern Wind" for the music title as a result).
00114                    //
00115                    // On real hardware it seems, attempts to write anywhere outside 0xxx56/0xxx57
00116                    // are ignored. They are not remapped. Attempts to write to 0x0056 are ignored
00117                    // by the hardware (since that conflicts with single-wide chars) but you can
00118                    // write to that cell if you write to 0x8056 instead.
00119             if ((a1_font_load_addr & 0x007E) == 0x0056 && (a1_font_load_addr & 0xFF00) != 0x0000)
00120                 pc98_font_char_write(a1_font_load_addr,a1_font_char_offset & 0xF,(a1_font_char_offset & 0x20) ? 0 : 1,(uint8_t)val);
00121             else
00122                 LOG_MSG("A1 port attempt to write FONT ROM char 0x%x",a1_font_load_addr);
00123             break;
00124         default:
00125             LOG_MSG("A1 port %lx val %lx unexpected",(unsigned long)port,(unsigned long)val);
00126             break;
00127     }
00128 }
00129