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 <math.h> 00021 #include <stdio.h> 00022 #include <stdlib.h> 00023 #include <string.h> 00024 #include "dosbox.h" 00025 #include "mem.h" 00026 #include "vga.h" 00027 #include "paging.h" 00028 #include "pic.h" 00029 #include "inout.h" 00030 #include "setup.h" 00031 #include "cpu.h" 00032 #include "pc98_cg.h" 00033 #include "pc98_gdc.h" 00034 #include "zipfile.h" 00035 00036 unsigned char pc98_pegc_mmio[0x200] = {0}; /* PC-98 memory-mapped PEGC registers at E0000h */ 00037 uint32_t pc98_pegc_banks[2] = {0x0000,0x0000}; /* bank switching offsets */ 00038 00039 extern bool non_cga_ignore_oddeven; 00040 extern bool non_cga_ignore_oddeven_engage; 00041 extern bool enable_pc98_256color_planar; 00042 extern bool enable_pc98_256color; 00043 00044 #ifndef C_VGARAM_CHECKED 00045 #define C_VGARAM_CHECKED 1 00046 #endif 00047 00048 #if C_VGARAM_CHECKED 00049 // Checked linear offset 00050 #define CHECKED(v) ((v)&vga.mem.memmask) 00051 // Checked planar offset (latched access) 00052 #define CHECKED2(v) ((v)&(vga.mem.memmask>>2)) 00053 #else 00054 #define CHECKED(v) (v) 00055 #define CHECKED2(v) (v) 00056 #endif 00057 00058 #define CHECKED3(v) ((v)&vga.mem.memmask) 00059 #define CHECKED4(v) ((v)&(vga.mem.memmask>>2)) 00060 00061 #define TANDY_VIDBASE(_X_) &MemBase[ 0x80000 + (_X_)] 00062 00063 /* how much delay to add to VGA memory I/O in nanoseconds */ 00064 int vga_memio_delay_ns = 1000; 00065 00066 void VGAMEM_USEC_read_delay() { 00067 if (vga_memio_delay_ns > 0) { 00068 Bits delaycyc = (CPU_CycleMax * vga_memio_delay_ns) / 1000000; 00069 // if(GCC_UNLIKELY(CPU_Cycles < 3*delaycyc)) delaycyc = 0; //Else port acces will set cycles to 0. which might trigger problem with games which read 16 bit values 00070 CPU_Cycles -= delaycyc; 00071 CPU_IODelayRemoved += delaycyc; 00072 } 00073 } 00074 00075 void VGAMEM_USEC_write_delay() { 00076 if (vga_memio_delay_ns > 0) { 00077 Bits delaycyc = (CPU_CycleMax * vga_memio_delay_ns * 3) / (1000000 * 4); 00078 // if(GCC_UNLIKELY(CPU_Cycles < 3*delaycyc)) delaycyc = 0; //Else port acces will set cycles to 0. which might trigger problem with games which read 16 bit values 00079 CPU_Cycles -= delaycyc; 00080 CPU_IODelayRemoved += delaycyc; 00081 } 00082 } 00083 00084 template <class Size> 00085 static INLINE void hostWrite(HostPt off, Bitu val) { 00086 if ( sizeof( Size ) == 1) 00087 host_writeb( off, (Bit8u)val ); 00088 else if ( sizeof( Size ) == 2) 00089 host_writew( off, (Bit16u)val ); 00090 else if ( sizeof( Size ) == 4) 00091 host_writed( off, (Bit32u)val ); 00092 } 00093 00094 template <class Size> 00095 static INLINE Bitu hostRead(HostPt off ) { 00096 if ( sizeof( Size ) == 1) 00097 return host_readb( off ); 00098 else if ( sizeof( Size ) == 2) 00099 return host_readw( off ); 00100 else if ( sizeof( Size ) == 4) 00101 return host_readd( off ); 00102 return 0; 00103 } 00104 00105 00106 void VGA_MapMMIO(void); 00107 //Nice one from DosEmu 00108 INLINE static Bit32u RasterOp(Bit32u input,Bit32u mask) { 00109 switch (vga.config.raster_op) { 00110 case 0x00: /* None */ 00111 return (input & mask) | (vga.latch.d & ~mask); 00112 case 0x01: /* AND */ 00113 return (input | ~mask) & vga.latch.d; 00114 case 0x02: /* OR */ 00115 return (input & mask) | vga.latch.d; 00116 case 0x03: /* XOR */ 00117 return (input & mask) ^ vga.latch.d; 00118 } 00119 return 0; 00120 } 00121 00122 INLINE static Bit32u ModeOperation(Bit8u val) { 00123 Bit32u full; 00124 switch (vga.config.write_mode) { 00125 case 0x00: 00126 // Write Mode 0: In this mode, the host data is first rotated as per the Rotate Count field, then the Enable Set/Reset mechanism selects data from this or the Set/Reset field. Then the selected Logical Operation is performed on the resulting data and the data in the latch register. Then the Bit Mask field is used to select which bits come from the resulting data and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory. 00127 val=((val >> vga.config.data_rotate) | (val << (8-vga.config.data_rotate))); 00128 full=ExpandTable[val]; 00129 full=(full & vga.config.full_not_enable_set_reset) | vga.config.full_enable_and_set_reset; 00130 full=RasterOp(full,vga.config.full_bit_mask); 00131 break; 00132 case 0x01: 00133 // Write Mode 1: In this mode, data is transferred directly from the 32 bit latch register to display memory, affected only by the Memory Plane Write Enable field. The host data is not used in this mode. 00134 full=vga.latch.d; 00135 break; 00136 case 0x02: 00137 //Write Mode 2: In this mode, the bits 3-0 of the host data are replicated across all 8 bits of their respective planes. Then the selected Logical Operation is performed on the resulting data and the data in the latch register. Then the Bit Mask field is used to select which bits come from the resulting data and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory. 00138 full=RasterOp(FillTable[val&0xF],vga.config.full_bit_mask); 00139 break; 00140 case 0x03: 00141 // Write Mode 3: In this mode, the data in the Set/Reset field is used as if the Enable Set/Reset field were set to 1111b. Then the host data is first rotated as per the Rotate Count field, then logical ANDed with the value of the Bit Mask field. The resulting value is used on the data obtained from the Set/Reset field in the same way that the Bit Mask field would ordinarily be used. to select which bits come from the expansion of the Set/Reset field and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory. 00142 val=((val >> vga.config.data_rotate) | (val << (8-vga.config.data_rotate))); 00143 full=RasterOp(vga.config.full_set_reset,ExpandTable[val] & vga.config.full_bit_mask); 00144 break; 00145 default: 00146 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:Unsupported write mode %d",vga.config.write_mode); 00147 full=0; 00148 break; 00149 } 00150 return full; 00151 } 00152 00153 bool pc98_pegc_linear_framebuffer_enabled(void) { 00154 return !!(pc98_pegc_mmio[0x102] & 1); 00155 } 00156 00157 // TODO: This code may have to handle 16-bit MMIO reads 00158 Bit8u pc98_pegc_mmio_read(unsigned int reg) { 00159 if (reg >= 0x200) 00160 return 0x00; 00161 00162 return pc98_pegc_mmio[reg]; 00163 } 00164 00165 // TODO: This code may have to handle 16-bit MMIO writes 00166 void pc98_pegc_mmio_write(unsigned int reg,Bit8u val) { 00167 if (reg >= 0x200) 00168 return; 00169 00170 Bit8u pval = pc98_pegc_mmio[reg]; 00171 00172 switch (reg) { 00173 case 0x004: // bank 0 00174 pc98_pegc_banks[0] = (val & 0xFu) << 15u; 00175 pc98_pegc_mmio[reg] = val; 00176 break; 00177 case 0x005: // unknown (WORD size write seen by bank switched (battle skin) and LFB (DOOM, DOOM2) games) 00178 // ignore 00179 break; 00180 case 0x006: // bank 1 00181 pc98_pegc_banks[1] = (val & 0xFu) << 15u; 00182 pc98_pegc_mmio[reg] = val; 00183 break; 00184 case 0x007: // unknown (WORD size write seen by bank switched (battle skin) and LFB (DOOM, DOOM2) games) 00185 // ignore 00186 break; 00187 case 0x100: // 256-color memory access (0=packed 1=planar) 00188 // WE DO NOT SUPPORT 256-planar MEMORY ACCESS AT THIS TIME! 00189 // FUTURE SUPPORT IS PLANNED. 00190 // ignore 00191 if (enable_pc98_256color_planar) { 00192 val &= 1; 00193 if (val & 1) { 00194 pc98_gdc_vramop |= (1 << VOPBIT_PEGC_PLANAR); 00195 LOG_MSG("PC-98 PEGC warning: Guest application/OS attempted to enable " 00196 "256-color planar mode, which is not yet fully functional"); 00197 } 00198 else { 00199 pc98_gdc_vramop &= ~(1 << VOPBIT_PEGC_PLANAR); 00200 } 00201 } 00202 else { 00203 if (val & 1) 00204 LOG_MSG("PC-98 PEGC warning: Guest application/OS attempted to enable " 00205 "256-color planar mode, which is not enabled in your configuration"); 00206 00207 val = 0; 00208 } 00209 pc98_pegc_mmio[reg] = val; 00210 if ((val^pval)&1/*if bit 0 changed*/) 00211 VGA_SetupHandlers(); 00212 break; 00213 case 0x102: // linear framebuffer (at F00000-F7FFFFh) enable/disable 00214 val &= 1; // as seen on real hardware: only bit 0 can be changed 00215 pc98_pegc_mmio[reg] = val; 00216 if ((val^pval)&1/*if bit 0 changed*/) 00217 VGA_SetupHandlers(); 00218 // FIXME: One PC-9821 laptop seems to allow bit 0 and bit 1 to be set. 00219 // What does bit 1 control? 00220 break; 00221 default: 00222 LOG_MSG("PC-98 PEGC warning: Unhandled write to %xh val %xh",reg+0xE0000u,val); 00223 break; 00224 } 00225 } 00226 00227 /* Gonna assume that whoever maps vga memory, maps it on 32/64kb boundary */ 00228 00229 #define VGA_PAGES (128/4) 00230 #define VGA_PAGE_A0 (0xA0000/4096) 00231 #define VGA_PAGE_B0 (0xB0000/4096) 00232 #define VGA_PAGE_B8 (0xB8000/4096) 00233 00234 static struct { 00235 Bitu base, mask; 00236 } vgapages; 00237 00238 static inline Bitu VGA_Generic_Read_Handler(PhysPt planeaddr,PhysPt rawaddr,unsigned char plane) { 00239 const unsigned char hobit_n = (vga.seq.memory_mode&2/*Extended Memory*/) ? 16u : 14u; 00240 00241 /* Sequencer Memory Mode Register (04h) 00242 * bits[3:3] = Chain 4 enable 00243 * bits[2:2] = Odd/Even Host Memory Write Addressing Disable 00244 * bits[1:1] = Extended memory (when EGA cards have > 64KB of RAM) 00245 * 00246 * NTS: Real hardware experience says that despite the name, the Odd/Even bit affects reading as well */ 00247 if (!(vga.seq.memory_mode&4) && !non_cga_ignore_oddeven_engage)/* Odd Even Host Memory Write Addressing Disable (is not set) */ 00248 plane = (plane & ~1u) + (rawaddr & 1u); 00249 00250 /* Graphics Controller: Miscellaneous Graphics Register register (06h) 00251 * bits[3:2] = memory map select 00252 * bits[1:1] = Chain Odd/Even Enable 00253 * bits[0:0] = Alphanumeric Mode Disable 00254 * 00255 * http://www.osdever.net/FreeVGA/vga/graphreg.htm 00256 * 00257 * When enabled, address bit A0 (bit 0) becomes bit 0 of the plane index. 00258 * Then when addressing VRAM A0 is replaced by a "higher order bit", which is 00259 * probably A14 or A16 depending on Extended Memory bit 1 in Sequencer register 04h memory mode */ 00260 if ((vga.gfx.miscellaneous&2) && !non_cga_ignore_oddeven_engage) {/* Odd/Even enable */ 00261 const PhysPt mask = (vga.config.compatible_chain4 ? 0u : ~0xFFFFu) + (1u << hobit_n) - 2u; 00262 const PhysPt hobit = (planeaddr >> hobit_n) & 1u; 00263 /* 1 << 14 = 0x4000 00264 * 1 << 14 - 1 = 0x3FFF 00265 * 1 << 14 - 2 = 0x3FFE 00266 * The point is to mask upper bit AND the LSB */ 00267 planeaddr = (planeaddr & mask & (vga.mem.memmask >> 2u)) + hobit; 00268 } 00269 else { 00270 const PhysPt mask = (vga.config.compatible_chain4 ? 0u : ~0xFFFFu) + (1u << hobit_n) - 1u; 00271 planeaddr &= mask & (vga.mem.memmask >> 2u); 00272 } 00273 00274 vga.latch.d=((Bit32u*)vga.mem.linear)[planeaddr]; 00275 switch (vga.config.read_mode) { 00276 case 0: 00277 return (vga.latch.b[plane]); 00278 case 1: 00279 VGA_Latch templatch; 00280 templatch.d=(vga.latch.d & FillTable[vga.config.color_dont_care]) ^ FillTable[vga.config.color_compare & vga.config.color_dont_care]; 00281 return (Bit8u)~(templatch.b[0] | templatch.b[1] | templatch.b[2] | templatch.b[3]); 00282 } 00283 00284 return 0; 00285 } 00286 00287 template <const bool chained> static inline void VGA_Generic_Write_Handler(PhysPt planeaddr,PhysPt rawaddr,Bit8u val) { 00288 const unsigned char hobit_n = (vga.seq.memory_mode&2/*Extended Memory*/) ? 16u : 14u; 00289 Bit32u mask = vga.config.full_map_mask; 00290 00291 /* Sequencer Memory Mode Register (04h) 00292 * bits[3:3] = Chain 4 enable 00293 * bits[2:2] = Odd/Even Host Memory Write Addressing Disable 00294 * bits[1:1] = Extended memory (when EGA cards have > 64KB of RAM) 00295 * 00296 * NTS: Real hardware experience says that despite the name, the Odd/Even bit affects reading as well */ 00297 if (chained) { 00298 if (!(vga.seq.memory_mode&4) && !non_cga_ignore_oddeven_engage)/* Odd Even Host Memory Write Addressing Disable (is not set) */ 00299 mask &= 0xFF00FFu << ((rawaddr & 1u) * 8u); 00300 else 00301 mask &= 0xFFu << ((rawaddr & 3u) * 8u); 00302 } 00303 else { 00304 if (!(vga.seq.memory_mode&4) && !non_cga_ignore_oddeven_engage)/* Odd Even Host Memory Write Addressing Disable (is not set) */ 00305 mask &= 0xFF00FFu << ((rawaddr & 1u) * 8u); 00306 } 00307 00308 /* Graphics Controller: Miscellaneous Graphics Register register (06h) 00309 * bits[3:2] = memory map select 00310 * bits[1:1] = Chain Odd/Even Enable 00311 * bits[0:0] = Alphanumeric Mode Disable 00312 * 00313 * http://www.osdever.net/FreeVGA/vga/graphreg.htm 00314 * 00315 * When enabled, address bit A0 (bit 0) becomes bit 0 of the plane index. 00316 * Then when addressing VRAM A0 is replaced by a "higher order bit", which is 00317 * probably A14 or A16 depending on Extended Memory bit 1 in Sequencer register 04h memory mode */ 00318 if ((vga.gfx.miscellaneous&2) && !non_cga_ignore_oddeven_engage) {/* Odd/Even enable */ 00319 const PhysPt mask = (vga.config.compatible_chain4 ? 0u : ~0xFFFFu) + (1u << hobit_n) - 2u; 00320 const PhysPt hobit = (planeaddr >> hobit_n) & 1u; 00321 /* 1 << 14 = 0x4000 00322 * 1 << 14 - 1 = 0x3FFF 00323 * 1 << 14 - 2 = 0x3FFE 00324 * The point is to mask upper bit AND the LSB */ 00325 planeaddr = (planeaddr & mask & (vga.mem.memmask >> 2u)) + hobit; 00326 } 00327 else { 00328 const PhysPt mask = (vga.config.compatible_chain4 ? 0u : ~0xFFFFu) + (1u << hobit_n) - 1u; 00329 planeaddr &= mask & (vga.mem.memmask >> 2u); 00330 } 00331 00332 Bit32u data=ModeOperation(val); 00333 VGA_Latch pixels; 00334 00335 pixels.d =((Bit32u*)vga.mem.linear)[planeaddr]; 00336 pixels.d&=~mask; 00337 pixels.d|=(data & mask); 00338 00339 /* FIXME: A better method (I think) is to have the VGA text drawing code 00340 * directly reference the font data in bitplane #2 instead of 00341 * this hack */ 00342 vga.draw.font[planeaddr] = pixels.b[2]; 00343 00344 ((Bit32u*)vga.mem.linear)[planeaddr]=pixels.d; 00345 } 00346 00347 // Slow accurate emulation. 00348 // This version takes the Graphics Controller bitmask and ROPs into account. 00349 // This is needed for demos that use the bitmask to do color combination or bitplane "page flipping" tricks. 00350 // This code will kick in if running in a chained VGA mode and the graphics controller bitmask register is 00351 // changed to anything other than 0xFF. 00352 // 00353 // Impact Studios "Legend" 00354 // - The rotating objects, rendered as dots, needs this hack because it uses a combination of masking off 00355 // bitplanes using the VGA DAC pel mask and drawing on the hidden bitplane using the Graphics Controller 00356 // bitmask. It also relies on loading the VGA latches with zeros as a form of "overdraw". Without this 00357 // version the effect will instead become a glowing ball of flickering yellow/red. 00358 class VGA_ChainedVGA_Slow_Handler : public PageHandler { 00359 public: 00360 VGA_ChainedVGA_Slow_Handler() : PageHandler(PFLAG_NOCODE) {} 00361 static INLINE Bitu readHandler8(PhysPt addr ) { 00362 // planar byte offset = addr & ~3u (discard low 2 bits) 00363 // planer index = addr & 3u (use low 2 bits as plane index) 00364 // FIXME: Does chained mode use the lower 2 bits of the CPU address or does it use the read mode select??? 00365 return VGA_Generic_Read_Handler(addr&~3u, addr, (Bit8u)(addr&3u)); 00366 } 00367 static INLINE void writeHandler8(PhysPt addr, Bitu val) { 00368 // planar byte offset = addr & ~3u (discard low 2 bits) 00369 // planer index = addr & 3u (use low 2 bits as plane index) 00370 return VGA_Generic_Write_Handler<true/*chained*/>(addr&~3u, addr, (Bit8u)val); 00371 } 00372 Bit8u readb(PhysPt addr ) { 00373 VGAMEM_USEC_read_delay(); 00374 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00375 addr += (PhysPt)vga.svga.bank_read_full; 00376 // addr = CHECKED(addr); 00377 return (Bit8u)readHandler8( addr ); 00378 } 00379 Bit16u readw(PhysPt addr ) { 00380 VGAMEM_USEC_read_delay(); 00381 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00382 addr += (PhysPt)vga.svga.bank_read_full; 00383 // addr = CHECKED(addr); 00384 Bit16u ret = (Bit16u)(readHandler8( addr+0 ) << 0 ); 00385 ret |= (readHandler8( addr+1 ) << 8 ); 00386 return ret; 00387 } 00388 Bit32u readd(PhysPt addr ) { 00389 VGAMEM_USEC_read_delay(); 00390 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00391 addr += (PhysPt)vga.svga.bank_read_full; 00392 // addr = CHECKED(addr); 00393 Bit32u ret = (Bit32u)(readHandler8( addr+0 ) << 0 ); 00394 ret |= (readHandler8( addr+1 ) << 8 ); 00395 ret |= (readHandler8( addr+2 ) << 16 ); 00396 ret |= (readHandler8( addr+3 ) << 24 ); 00397 return ret; 00398 } 00399 void writeb(PhysPt addr, Bit8u val ) { 00400 VGAMEM_USEC_write_delay(); 00401 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00402 addr += (PhysPt)vga.svga.bank_write_full; 00403 // addr = CHECKED(addr); 00404 writeHandler8( addr, val ); 00405 } 00406 void writew(PhysPt addr,Bit16u val) { 00407 VGAMEM_USEC_write_delay(); 00408 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00409 addr += (PhysPt)vga.svga.bank_write_full; 00410 // addr = CHECKED(addr); 00411 writeHandler8( addr+0, (Bit8u)(val >> 0u) ); 00412 writeHandler8( addr+1, (Bit8u)(val >> 8u) ); 00413 } 00414 void writed(PhysPt addr,Bit32u val) { 00415 VGAMEM_USEC_write_delay(); 00416 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00417 addr += (PhysPt)vga.svga.bank_write_full; 00418 // addr = CHECKED(addr); 00419 writeHandler8( addr+0, (Bit8u)(val >> 0u) ); 00420 writeHandler8( addr+1, (Bit8u)(val >> 8u) ); 00421 writeHandler8( addr+2, (Bit8u)(val >> 16u) ); 00422 writeHandler8( addr+3, (Bit8u)(val >> 24u) ); 00423 } 00424 }; 00425 00426 class VGA_ET4000_ChainedVGA_Slow_Handler : public PageHandler { 00427 public: 00428 VGA_ET4000_ChainedVGA_Slow_Handler() : PageHandler(PFLAG_NOCODE) {} 00429 static INLINE Bitu readHandler8(PhysPt addr ) { 00430 // planar byte offset = addr >> 2 (shift 2 bits to the right) 00431 // planer index = addr & 3u (use low 2 bits as plane index) 00432 return VGA_Generic_Read_Handler(addr>>2u, addr, (Bit8u)(addr&3u)); 00433 } 00434 static INLINE void writeHandler8(PhysPt addr, Bitu val) { 00435 // planar byte offset = addr >> 2 (shift 2 bits to the right) 00436 // planer index = addr & 3u (use low 2 bits as plane index) 00437 return VGA_Generic_Write_Handler<true/*chained*/>(addr>>2u, addr, (Bit8u)val); 00438 } 00439 Bit8u readb(PhysPt addr ) { 00440 VGAMEM_USEC_read_delay(); 00441 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00442 addr += (PhysPt)vga.svga.bank_read_full; 00443 // addr = CHECKED(addr); 00444 return (Bit8u)readHandler8( addr ); 00445 } 00446 Bit16u readw(PhysPt addr ) { 00447 VGAMEM_USEC_read_delay(); 00448 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00449 addr += (PhysPt)vga.svga.bank_read_full; 00450 // addr = CHECKED(addr); 00451 Bit16u ret = (Bit16u)(readHandler8( addr+0 ) << 0 ); 00452 ret |= (readHandler8( addr+1 ) << 8 ); 00453 return ret; 00454 } 00455 Bit32u readd(PhysPt addr ) { 00456 VGAMEM_USEC_read_delay(); 00457 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00458 addr += (PhysPt)vga.svga.bank_read_full; 00459 // addr = CHECKED(addr); 00460 Bit32u ret = (Bit32u)(readHandler8( addr+0 ) << 0 ); 00461 ret |= (readHandler8( addr+1 ) << 8 ); 00462 ret |= (readHandler8( addr+2 ) << 16 ); 00463 ret |= (readHandler8( addr+3 ) << 24 ); 00464 return ret; 00465 } 00466 void writeb(PhysPt addr, Bit8u val ) { 00467 VGAMEM_USEC_write_delay(); 00468 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00469 addr += (PhysPt)vga.svga.bank_write_full; 00470 // addr = CHECKED(addr); 00471 writeHandler8( addr, val ); 00472 } 00473 void writew(PhysPt addr,Bit16u val) { 00474 VGAMEM_USEC_write_delay(); 00475 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00476 addr += (PhysPt)vga.svga.bank_write_full; 00477 // addr = CHECKED(addr); 00478 writeHandler8( addr+0, (Bit8u)(val >> 0u) ); 00479 writeHandler8( addr+1, (Bit8u)(val >> 8u) ); 00480 } 00481 void writed(PhysPt addr,Bit32u val) { 00482 VGAMEM_USEC_write_delay(); 00483 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00484 addr += (PhysPt)vga.svga.bank_write_full; 00485 // addr = CHECKED(addr); 00486 writeHandler8( addr+0, (Bit8u)(val >> 0u) ); 00487 writeHandler8( addr+1, (Bit8u)(val >> 8u) ); 00488 writeHandler8( addr+2, (Bit8u)(val >> 16u) ); 00489 writeHandler8( addr+3, (Bit8u)(val >> 24u) ); 00490 } 00491 }; 00492 00493 class VGA_UnchainedVGA_Handler : public PageHandler { 00494 public: 00495 Bitu readHandler(PhysPt start) { 00496 return VGA_Generic_Read_Handler(start, start, vga.config.read_map_select); 00497 } 00498 public: 00499 Bit8u readb(PhysPt addr) { 00500 VGAMEM_USEC_read_delay(); 00501 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00502 addr += (PhysPt)vga.svga.bank_read_full; 00503 // addr = CHECKED2(addr); 00504 return (Bit8u)readHandler(addr); 00505 } 00506 Bit16u readw(PhysPt addr) { 00507 VGAMEM_USEC_read_delay(); 00508 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00509 addr += (PhysPt)vga.svga.bank_read_full; 00510 // addr = CHECKED2(addr); 00511 Bit16u ret = (Bit16u)(readHandler(addr+0) << 0); 00512 ret |= (readHandler(addr+1) << 8); 00513 return ret; 00514 } 00515 Bit32u readd(PhysPt addr) { 00516 VGAMEM_USEC_read_delay(); 00517 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00518 addr += (PhysPt)vga.svga.bank_read_full; 00519 // addr = CHECKED2(addr); 00520 Bit32u ret = (Bit32u)(readHandler(addr+0) << 0); 00521 ret |= (readHandler(addr+1) << 8); 00522 ret |= (readHandler(addr+2) << 16); 00523 ret |= (readHandler(addr+3) << 24); 00524 return ret; 00525 } 00526 public: 00527 void writeHandler(PhysPt start, Bit8u val) { 00528 VGA_Generic_Write_Handler<false/*chained*/>(start, start, val); 00529 } 00530 public: 00531 VGA_UnchainedVGA_Handler() : PageHandler(PFLAG_NOCODE) {} 00532 void writeb(PhysPt addr,Bit8u val) { 00533 VGAMEM_USEC_write_delay(); 00534 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00535 addr += (PhysPt)vga.svga.bank_write_full; 00536 // addr = CHECKED2(addr); 00537 writeHandler(addr+0,(Bit8u)(val >> 0)); 00538 } 00539 void writew(PhysPt addr,Bit16u val) { 00540 VGAMEM_USEC_write_delay(); 00541 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00542 addr += (PhysPt)vga.svga.bank_write_full; 00543 // addr = CHECKED2(addr); 00544 writeHandler(addr+0,(Bit8u)(val >> 0)); 00545 writeHandler(addr+1,(Bit8u)(val >> 8)); 00546 } 00547 void writed(PhysPt addr,Bit32u val) { 00548 VGAMEM_USEC_write_delay(); 00549 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; 00550 addr += (PhysPt)vga.svga.bank_write_full; 00551 // addr = CHECKED2(addr); 00552 writeHandler(addr+0,(Bit8u)(val >> 0)); 00553 writeHandler(addr+1,(Bit8u)(val >> 8)); 00554 writeHandler(addr+2,(Bit8u)(val >> 16)); 00555 writeHandler(addr+3,(Bit8u)(val >> 24)); 00556 } 00557 }; 00558 00559 #include <stdio.h> 00560 00561 class VGA_CGATEXT_PageHandler : public PageHandler { 00562 public: 00563 VGA_CGATEXT_PageHandler() { 00564 flags=PFLAG_NOCODE; 00565 } 00566 Bit8u readb(PhysPt addr) { 00567 addr = PAGING_GetPhysicalAddress(addr) & 0x3FFF; 00568 VGAMEM_USEC_read_delay(); 00569 return vga.tandy.mem_base[addr]; 00570 } 00571 void writeb(PhysPt addr,Bit8u val){ 00572 VGAMEM_USEC_write_delay(); 00573 00574 if (enableCGASnow) { 00575 /* NTS: We can't use PIC_FullIndex() exclusively because it's not precise enough 00576 * with respect to when DOSBox CPU emulation is writing. We have to use other 00577 * variables like CPU_Cycles to gain additional precision */ 00578 double timeInFrame = PIC_FullIndex()-vga.draw.delay.framestart; 00579 double timeInLine = fmod(timeInFrame,vga.draw.delay.htotal); 00580 00581 /* we're in active area. which column should the snow show up on? */ 00582 Bit32u x = (Bit32u)((timeInLine * 80) / vga.draw.delay.hblkstart); 00583 if ((unsigned)x < 80) vga.draw.cga_snow[x] = val; 00584 } 00585 00586 addr = PAGING_GetPhysicalAddress(addr) & 0x3FFF; 00587 vga.tandy.mem_base[addr] = val; 00588 } 00589 }; 00590 00591 class VGA_MCGATEXT_PageHandler : public PageHandler { 00592 public: 00593 VGA_MCGATEXT_PageHandler() { 00594 flags=PFLAG_NOCODE; 00595 } 00596 Bit8u readb(PhysPt addr) { 00597 addr = PAGING_GetPhysicalAddress(addr) & 0xFFFF; 00598 VGAMEM_USEC_read_delay(); 00599 return vga.tandy.mem_base[addr]; 00600 } 00601 void writeb(PhysPt addr,Bit8u val){ 00602 VGAMEM_USEC_write_delay(); 00603 00604 addr = PAGING_GetPhysicalAddress(addr) & 0xFFFF; 00605 vga.tandy.mem_base[addr] = val; 00606 } 00607 }; 00608 00609 extern uint8_t pc98_egc_srcmask[2]; /* host given (Neko: egc.srcmask) */ 00610 extern uint8_t pc98_egc_maskef[2]; /* effective (Neko: egc.mask2) */ 00611 extern uint8_t pc98_egc_mask[2]; /* host given (Neko: egc.mask) */ 00612 extern uint8_t pc98_egc_access; 00613 extern uint8_t pc98_egc_fgc; 00614 extern uint8_t pc98_egc_foreground_color; 00615 extern uint8_t pc98_egc_background_color; 00616 extern uint8_t pc98_egc_lead_plane; 00617 extern uint8_t pc98_egc_compare_lead; 00618 extern uint8_t pc98_egc_lightsource; 00619 extern uint8_t pc98_egc_shiftinput; 00620 extern uint8_t pc98_egc_regload; 00621 extern uint8_t pc98_egc_rop; 00622 00623 extern bool pc98_egc_shift_descend; 00624 extern uint8_t pc98_egc_shift_destbit; 00625 extern uint8_t pc98_egc_shift_srcbit; 00626 extern uint16_t pc98_egc_shift_length; 00627 00628 /* I don't think we necessarily need the full 4096 bit buffer 00629 * Neko Project II uses to render things, though that is 00630 * probably faster to execute. It makes it hard to make sense 00631 * of the code though. */ 00632 struct pc98_egc_shifter { 00633 pc98_egc_shifter() : decrement(false), remain(0x10), srcbit(0), dstbit(0) { } 00634 00635 void reinit(void) { /* from global vars set by guest */ 00636 decrement = pc98_egc_shift_descend; 00637 remain = pc98_egc_shift_length + 1; /* the register is length - 1 apparently */ 00638 dstbit = pc98_egc_shift_destbit; 00639 srcbit = pc98_egc_shift_srcbit; 00640 bufi = bufo = decrement ? (sizeof(buffer) + 3 - (4*4)) : 0; 00641 00642 if ((srcbit&7) < (dstbit&7)) { 00643 shft8bitr = (dstbit&7) - (srcbit&7); 00644 shft8bitl = 8 - shft8bitr; 00645 } 00646 else if ((srcbit&7) > (dstbit&7)) { 00647 shft8bitl = (srcbit&7) - (dstbit&7); 00648 shft8bitr = 8 - shft8bitl; 00649 } 00650 else { 00651 shft8bitr = 0; 00652 shft8bitl = 0; 00653 } 00654 00655 shft8load = 0; 00656 o_srcbit = srcbit & 7; 00657 o_dstbit = dstbit & 7; 00658 } 00659 00660 bool decrement; 00661 uint16_t remain; 00662 uint16_t srcbit; 00663 uint16_t dstbit; 00664 uint16_t o_srcbit = 0; 00665 uint16_t o_dstbit = 0; 00666 00667 uint8_t buffer[512] = {}; /* 4096/8 = 512 */ 00668 uint16_t bufi = 0, bufo = 0; 00669 00670 uint8_t shft8load = 0; 00671 uint8_t shft8bitr = 0; 00672 uint8_t shft8bitl = 0; 00673 00674 std::string debug_status(void) { 00675 char tmp[512]; 00676 00677 sprintf(tmp,"decrement=%u remain=%u srcbit=%u dstbit=%u shf8l=%u shf8br=%u shf8bl=%u", 00678 decrement?1:0, 00679 remain, 00680 srcbit, 00681 dstbit, 00682 shft8load, 00683 shft8bitr, 00684 shft8bitl); 00685 00686 return std::string(tmp); 00687 } 00688 00689 template <class AWT> inline void bi(const uint16_t ofs,const AWT val) { 00690 size_t ip = (bufi + ofs) & (sizeof(buffer) - 1); 00691 00692 for (size_t i=0;i < sizeof(AWT);) { 00693 buffer[ip] = (uint8_t)(val >> ((AWT)(i * 8U))); 00694 if ((++ip) == sizeof(buffer)) ip = 0; 00695 i++; 00696 } 00697 } 00698 00699 template <class AWT> inline void bi_adv(void) { 00700 bufi += pc98_egc_shift_descend ? (sizeof(buffer) - sizeof(AWT)) : sizeof(AWT); 00701 bufi &= (sizeof(buffer) - 1); 00702 } 00703 00704 template <class AWT> inline AWT bo(const uint16_t ofs) { 00705 size_t op = (bufo + ofs) & (sizeof(buffer) - 1); 00706 AWT ret = 0; 00707 00708 for (size_t i=0;i < sizeof(AWT);) { 00709 ret += ((AWT)buffer[op]) << ((AWT)(i * 8U)); 00710 if ((++op) == sizeof(buffer)) op = 0; 00711 i++; 00712 } 00713 00714 return ret; 00715 } 00716 00717 template <class AWT> inline void bo_adv(void) { 00718 bufo += pc98_egc_shift_descend ? (sizeof(buffer) - sizeof(AWT)) : sizeof(AWT); 00719 bufo &= (sizeof(buffer) - 1); 00720 } 00721 00722 template <class AWT> inline void input(const AWT a,const AWT b,const AWT c,const AWT d,uint8_t odd) { 00723 bi<AWT>((pc98_egc_shift_descend ? (sizeof(buffer) + 1 - sizeof(AWT)) : 0) + 0,a); 00724 bi<AWT>((pc98_egc_shift_descend ? (sizeof(buffer) + 1 - sizeof(AWT)) : 0) + 4,b); 00725 bi<AWT>((pc98_egc_shift_descend ? (sizeof(buffer) + 1 - sizeof(AWT)) : 0) + 8,c); 00726 bi<AWT>((pc98_egc_shift_descend ? (sizeof(buffer) + 1 - sizeof(AWT)) : 0) + 12,d); 00727 00728 if (shft8load <= 16) { 00729 bi_adv<AWT>(); 00730 00731 if (sizeof(AWT) == 2) { 00732 if (srcbit >= 8) bo_adv<uint8_t>(); 00733 shft8load += (16 - srcbit); 00734 srcbit = 0; 00735 } 00736 else { 00737 if (srcbit >= 8) 00738 srcbit -= 8; 00739 else { 00740 shft8load += (8 - srcbit); 00741 srcbit = 0; 00742 } 00743 } 00744 } 00745 00746 *((AWT*)(pc98_egc_srcmask+odd)) = (AWT)(~0ull); 00747 } 00748 00749 inline uint8_t dstbit_mask(void) { 00750 uint8_t mb; 00751 00752 /* assume remain > 0 */ 00753 if (remain >= 8) 00754 mb = 0xFF; 00755 else if (!pc98_egc_shift_descend) 00756 mb = 0xFF << (uint8_t)(8 - remain); /* 0x80 0xC0 0xE0 0xF0 ... */ 00757 else 00758 mb = 0xFF >> (uint8_t)(8 - remain); /* 0x01 0x03 0x07 0x0F ... */ 00759 00760 /* assume dstbit < 8 */ 00761 if (!pc98_egc_shift_descend) 00762 return mb >> (uint8_t)dstbit; /* 0xFF 0x7F 0x3F 0x1F ... */ 00763 else 00764 return mb << (uint8_t)dstbit; /* 0xFF 0xFE 0xFC 0xF8 ... */ 00765 } 00766 00767 template <class AWT> inline void output(AWT &a,AWT &b,AWT &c,AWT &d,uint8_t odd,bool recursive=false) { 00768 if (sizeof(AWT) == 2) { 00769 if (shft8load < (16 - dstbit)) { 00770 *((AWT*)(pc98_egc_srcmask+odd)) = 0; 00771 return; 00772 } 00773 shft8load -= (16 - dstbit); 00774 00775 /* assume odd == false and output is to even byte offset */ 00776 if (pc98_egc_shift_descend) { 00777 output<uint8_t>(((uint8_t*)(&a))[1],((uint8_t*)(&b))[1],((uint8_t*)(&c))[1],((uint8_t*)(&d))[1],1,true); 00778 if (remain != 0) output<uint8_t>(((uint8_t*)(&a))[0],((uint8_t*)(&b))[0],((uint8_t*)(&c))[0],((uint8_t*)(&d))[0],0,true); 00779 else pc98_egc_srcmask[0] = 0; 00780 } 00781 else { 00782 output<uint8_t>(((uint8_t*)(&a))[0],((uint8_t*)(&b))[0],((uint8_t*)(&c))[0],((uint8_t*)(&d))[0],0,true); 00783 if (remain != 0) output<uint8_t>(((uint8_t*)(&a))[1],((uint8_t*)(&b))[1],((uint8_t*)(&c))[1],((uint8_t*)(&d))[1],1,true); 00784 else pc98_egc_srcmask[1] = 0; 00785 } 00786 00787 if (remain == 0) 00788 reinit(); 00789 00790 return; 00791 } 00792 00793 if (!recursive) { 00794 if (shft8load < (8 - dstbit)) { 00795 *((AWT*)(pc98_egc_srcmask+odd)) = 0; 00796 return; 00797 } 00798 shft8load -= (8 - dstbit); 00799 } 00800 00801 if (dstbit >= 8) { 00802 dstbit -= 8; 00803 *((AWT*)(pc98_egc_srcmask+odd)) = 0; 00804 return; 00805 } 00806 00807 *((AWT*)(pc98_egc_srcmask+odd)) = dstbit_mask(); 00808 00809 if (dstbit > 0) { 00810 const uint8_t bc = 8 - dstbit; 00811 00812 if (remain >= bc) 00813 remain -= bc; 00814 else 00815 remain = 0; 00816 } 00817 else { 00818 if (remain >= 8) 00819 remain -= 8; 00820 else 00821 remain = 0; 00822 } 00823 00824 if (o_srcbit < o_dstbit) { 00825 if (dstbit != 0) { 00826 if (pc98_egc_shift_descend) { 00827 a = bo<AWT>( 0) << shft8bitr; 00828 b = bo<AWT>( 4) << shft8bitr; 00829 c = bo<AWT>( 8) << shft8bitr; 00830 d = bo<AWT>(12) << shft8bitr; 00831 } 00832 else { 00833 a = bo<AWT>( 0) >> shft8bitr; 00834 b = bo<AWT>( 4) >> shft8bitr; 00835 c = bo<AWT>( 8) >> shft8bitr; 00836 d = bo<AWT>(12) >> shft8bitr; 00837 } 00838 00839 dstbit = 0; 00840 } 00841 else { 00842 if (pc98_egc_shift_descend) { 00843 bo_adv<AWT>(); 00844 a = (bo<AWT>( 0+1) >> shft8bitl) | (bo<AWT>( 0) << shft8bitr); 00845 b = (bo<AWT>( 4+1) >> shft8bitl) | (bo<AWT>( 4) << shft8bitr); 00846 c = (bo<AWT>( 8+1) >> shft8bitl) | (bo<AWT>( 8) << shft8bitr); 00847 d = (bo<AWT>(12+1) >> shft8bitl) | (bo<AWT>(12) << shft8bitr); 00848 } 00849 else { 00850 a = (bo<AWT>( 0) << shft8bitl) | (bo<AWT>( 0+1) >> shft8bitr); 00851 b = (bo<AWT>( 4) << shft8bitl) | (bo<AWT>( 4+1) >> shft8bitr); 00852 c = (bo<AWT>( 8) << shft8bitl) | (bo<AWT>( 8+1) >> shft8bitr); 00853 d = (bo<AWT>(12) << shft8bitl) | (bo<AWT>(12+1) >> shft8bitr); 00854 bo_adv<AWT>(); 00855 } 00856 } 00857 } 00858 else if (o_srcbit > o_dstbit) { 00859 dstbit = 0; 00860 00861 if (pc98_egc_shift_descend) { 00862 bo_adv<AWT>(); 00863 a = (bo<AWT>( 0+1) >> shft8bitl) | (bo<AWT>( 0) << shft8bitr); 00864 b = (bo<AWT>( 4+1) >> shft8bitl) | (bo<AWT>( 4) << shft8bitr); 00865 c = (bo<AWT>( 8+1) >> shft8bitl) | (bo<AWT>( 8) << shft8bitr); 00866 d = (bo<AWT>(12+1) >> shft8bitl) | (bo<AWT>(12) << shft8bitr); 00867 } 00868 else { 00869 a = (bo<AWT>( 0) << shft8bitl) | (bo<AWT>( 0+1) >> shft8bitr); 00870 b = (bo<AWT>( 4) << shft8bitl) | (bo<AWT>( 4+1) >> shft8bitr); 00871 c = (bo<AWT>( 8) << shft8bitl) | (bo<AWT>( 8+1) >> shft8bitr); 00872 d = (bo<AWT>(12) << shft8bitl) | (bo<AWT>(12+1) >> shft8bitr); 00873 bo_adv<AWT>(); 00874 } 00875 } 00876 else { 00877 dstbit = 0; 00878 00879 a = bo<AWT>( 0); 00880 b = bo<AWT>( 4); 00881 c = bo<AWT>( 8); 00882 d = bo<AWT>(12); 00883 bo_adv<AWT>(); 00884 } 00885 00886 if (!recursive && remain == 0) 00887 reinit(); 00888 } 00889 }; 00890 00891 egc_quad pc98_egc_src; 00892 egc_quad pc98_egc_bgcm; 00893 egc_quad pc98_egc_fgcm; 00894 egc_quad pc98_egc_data; 00895 egc_quad pc98_egc_last_vram; 00896 00897 pc98_egc_shifter pc98_egc_shift; 00898 00899 std::string pc98_egc_shift_debug_status(void) { 00900 return pc98_egc_shift.debug_status(); 00901 } 00902 00903 typedef egc_quad & (*PC98_OPEFN)(uint8_t ope, const PhysPt ad); 00904 00905 void pc98_egc_shift_reinit() { 00906 pc98_egc_shift.reinit(); 00907 } 00908 00909 template <class AWT> static inline void egc_fetch_planar(egc_quad &dst,const PhysPt vramoff) { 00910 dst[0].w = *((uint16_t*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(0))); 00911 dst[1].w = *((uint16_t*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(1))); 00912 dst[2].w = *((uint16_t*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(2))); 00913 dst[3].w = *((uint16_t*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(3))); 00914 } 00915 00916 static egc_quad &ope_xx(uint8_t ope, const PhysPt ad) { 00917 (void)ad;//UNUSED 00918 LOG_MSG("EGC ROP 0x%2x not impl",ope); 00919 return pc98_egc_last_vram; 00920 } 00921 00922 static egc_quad &ope_00(uint8_t ope, const PhysPt vramoff) { 00923 (void)vramoff; 00924 (void)ope; 00925 00926 pc98_egc_data[0].w = 0; 00927 pc98_egc_data[1].w = 0; 00928 pc98_egc_data[2].w = 0; 00929 pc98_egc_data[3].w = 0; 00930 00931 return pc98_egc_data; 00932 } 00933 00934 static egc_quad &ope_0f(uint8_t ope, const PhysPt vramoff) { 00935 (void)vramoff; 00936 (void)ope; 00937 00938 pc98_egc_data[0].w = ~pc98_egc_src[0].w; 00939 pc98_egc_data[1].w = ~pc98_egc_src[1].w; 00940 pc98_egc_data[2].w = ~pc98_egc_src[2].w; 00941 pc98_egc_data[3].w = ~pc98_egc_src[3].w; 00942 00943 return pc98_egc_data; 00944 } 00945 00946 static egc_quad &ope_ff(uint8_t ope, const PhysPt vramoff) { 00947 (void)vramoff; 00948 (void)ope; 00949 00950 pc98_egc_data[0].w = (Bit16u)(~0u); 00951 pc98_egc_data[1].w = (Bit16u)(~0u); 00952 pc98_egc_data[2].w = (Bit16u)(~0u); 00953 pc98_egc_data[3].w = (Bit16u)(~0u); 00954 00955 return pc98_egc_data; 00956 } 00957 00958 static egc_quad &ope_np(uint8_t ope, const PhysPt vramoff) { 00959 egc_quad dst; 00960 00961 egc_fetch_planar<uint16_t>(/*&*/dst,vramoff); 00962 00963 pc98_egc_data[0].w = 0; 00964 pc98_egc_data[1].w = 0; 00965 pc98_egc_data[2].w = 0; 00966 pc98_egc_data[3].w = 0; 00967 00968 if (ope & 0x80) { 00969 pc98_egc_data[0].w |= (pc98_egc_src[0].w & dst[0].w); 00970 pc98_egc_data[1].w |= (pc98_egc_src[1].w & dst[1].w); 00971 pc98_egc_data[2].w |= (pc98_egc_src[2].w & dst[2].w); 00972 pc98_egc_data[3].w |= (pc98_egc_src[3].w & dst[3].w); 00973 } 00974 if (ope & 0x20) { 00975 pc98_egc_data[0].w |= (pc98_egc_src[0].w & (~dst[0].w)); 00976 pc98_egc_data[1].w |= (pc98_egc_src[1].w & (~dst[1].w)); 00977 pc98_egc_data[2].w |= (pc98_egc_src[2].w & (~dst[2].w)); 00978 pc98_egc_data[3].w |= (pc98_egc_src[3].w & (~dst[3].w)); 00979 } 00980 if (ope & 0x08) { 00981 pc98_egc_data[0].w |= ((~pc98_egc_src[0].w) & dst[0].w); 00982 pc98_egc_data[1].w |= ((~pc98_egc_src[1].w) & dst[1].w); 00983 pc98_egc_data[2].w |= ((~pc98_egc_src[2].w) & dst[2].w); 00984 pc98_egc_data[3].w |= ((~pc98_egc_src[3].w) & dst[3].w); 00985 } 00986 if (ope & 0x02) { 00987 pc98_egc_data[0].w |= ((~pc98_egc_src[0].w) & (~dst[0].w)); 00988 pc98_egc_data[1].w |= ((~pc98_egc_src[1].w) & (~dst[1].w)); 00989 pc98_egc_data[2].w |= ((~pc98_egc_src[2].w) & (~dst[2].w)); 00990 pc98_egc_data[3].w |= ((~pc98_egc_src[3].w) & (~dst[3].w)); 00991 } 00992 00993 (void)ope; 00994 (void)vramoff; 00995 return pc98_egc_data; 00996 } 00997 00998 static egc_quad &ope_nd(uint8_t ope, const PhysPt vramoff) { 00999 egc_quad pat; 01000 01001 switch(pc98_egc_fgc) { 01002 case 1: 01003 pat[0].w = pc98_egc_bgcm[0].w; 01004 pat[1].w = pc98_egc_bgcm[1].w; 01005 pat[2].w = pc98_egc_bgcm[2].w; 01006 pat[3].w = pc98_egc_bgcm[3].w; 01007 break; 01008 01009 case 2: 01010 pat[0].w = pc98_egc_fgcm[0].w; 01011 pat[1].w = pc98_egc_fgcm[1].w; 01012 pat[2].w = pc98_egc_fgcm[2].w; 01013 pat[3].w = pc98_egc_fgcm[3].w; 01014 break; 01015 01016 default: 01017 if (pc98_egc_regload & 1) { 01018 pat[0].w = pc98_egc_src[0].w; 01019 pat[1].w = pc98_egc_src[1].w; 01020 pat[2].w = pc98_egc_src[2].w; 01021 pat[3].w = pc98_egc_src[3].w; 01022 } 01023 else { 01024 pat[0].w = pc98_gdc_tiles[0].w; 01025 pat[1].w = pc98_gdc_tiles[1].w; 01026 pat[2].w = pc98_gdc_tiles[2].w; 01027 pat[3].w = pc98_gdc_tiles[3].w; 01028 } 01029 break; 01030 } 01031 01032 pc98_egc_data[0].w = 0; 01033 pc98_egc_data[1].w = 0; 01034 pc98_egc_data[2].w = 0; 01035 pc98_egc_data[3].w = 0; 01036 01037 if (ope & 0x80) { 01038 pc98_egc_data[0].w |= (pat[0].w & pc98_egc_src[0].w); 01039 pc98_egc_data[1].w |= (pat[1].w & pc98_egc_src[1].w); 01040 pc98_egc_data[2].w |= (pat[2].w & pc98_egc_src[2].w); 01041 pc98_egc_data[3].w |= (pat[3].w & pc98_egc_src[3].w); 01042 } 01043 if (ope & 0x40) { 01044 pc98_egc_data[0].w |= ((~pat[0].w) & pc98_egc_src[0].w); 01045 pc98_egc_data[1].w |= ((~pat[1].w) & pc98_egc_src[1].w); 01046 pc98_egc_data[2].w |= ((~pat[2].w) & pc98_egc_src[2].w); 01047 pc98_egc_data[3].w |= ((~pat[3].w) & pc98_egc_src[3].w); 01048 } 01049 if (ope & 0x08) { 01050 pc98_egc_data[0].w |= (pat[0].w & (~pc98_egc_src[0].w)); 01051 pc98_egc_data[1].w |= (pat[1].w & (~pc98_egc_src[1].w)); 01052 pc98_egc_data[2].w |= (pat[2].w & (~pc98_egc_src[2].w)); 01053 pc98_egc_data[3].w |= (pat[3].w & (~pc98_egc_src[3].w)); 01054 } 01055 if (ope & 0x04) { 01056 pc98_egc_data[0].w |= ((~pat[0].w) & (~pc98_egc_src[0].w)); 01057 pc98_egc_data[1].w |= ((~pat[1].w) & (~pc98_egc_src[1].w)); 01058 pc98_egc_data[2].w |= ((~pat[2].w) & (~pc98_egc_src[2].w)); 01059 pc98_egc_data[3].w |= ((~pat[3].w) & (~pc98_egc_src[3].w)); 01060 } 01061 01062 (void)ope; 01063 (void)vramoff; 01064 return pc98_egc_data; 01065 } 01066 01067 static egc_quad &ope_c0(uint8_t ope, const PhysPt vramoff) { 01068 egc_quad dst; 01069 01070 /* assume: ad is word aligned */ 01071 01072 egc_fetch_planar<uint16_t>(/*&*/dst,vramoff); 01073 01074 pc98_egc_data[0].w = pc98_egc_src[0].w & dst[0].w; 01075 pc98_egc_data[1].w = pc98_egc_src[1].w & dst[1].w; 01076 pc98_egc_data[2].w = pc98_egc_src[2].w & dst[2].w; 01077 pc98_egc_data[3].w = pc98_egc_src[3].w & dst[3].w; 01078 01079 (void)ope; 01080 (void)vramoff; 01081 return pc98_egc_data; 01082 } 01083 01084 static egc_quad &ope_f0(uint8_t ope, const PhysPt vramoff) { 01085 (void)ope; 01086 (void)vramoff; 01087 return pc98_egc_src; 01088 } 01089 01090 static egc_quad &ope_fc(uint8_t ope, const PhysPt vramoff) { 01091 egc_quad dst; 01092 01093 /* assume: ad is word aligned */ 01094 01095 egc_fetch_planar<uint16_t>(/*&*/dst,vramoff); 01096 01097 pc98_egc_data[0].w = pc98_egc_src[0].w; 01098 pc98_egc_data[0].w |= ((~pc98_egc_src[0].w) & dst[0].w); 01099 pc98_egc_data[1].w = pc98_egc_src[1].w; 01100 pc98_egc_data[1].w |= ((~pc98_egc_src[1].w) & dst[1].w); 01101 pc98_egc_data[2].w = pc98_egc_src[2].w; 01102 pc98_egc_data[2].w |= ((~pc98_egc_src[2].w) & dst[2].w); 01103 pc98_egc_data[3].w = pc98_egc_src[3].w; 01104 pc98_egc_data[3].w |= ((~pc98_egc_src[3].w) & dst[3].w); 01105 01106 (void)ope; 01107 (void)vramoff; 01108 return pc98_egc_data; 01109 } 01110 01111 static egc_quad &ope_gg(uint8_t ope, const PhysPt vramoff) { 01112 egc_quad pat,dst; 01113 01114 switch(pc98_egc_fgc) { 01115 case 1: 01116 pat[0].w = pc98_egc_bgcm[0].w; 01117 pat[1].w = pc98_egc_bgcm[1].w; 01118 pat[2].w = pc98_egc_bgcm[2].w; 01119 pat[3].w = pc98_egc_bgcm[3].w; 01120 break; 01121 01122 case 2: 01123 pat[0].w = pc98_egc_fgcm[0].w; 01124 pat[1].w = pc98_egc_fgcm[1].w; 01125 pat[2].w = pc98_egc_fgcm[2].w; 01126 pat[3].w = pc98_egc_fgcm[3].w; 01127 break; 01128 01129 default: 01130 if (pc98_egc_regload & 1) { 01131 pat[0].w = pc98_egc_src[0].w; 01132 pat[1].w = pc98_egc_src[1].w; 01133 pat[2].w = pc98_egc_src[2].w; 01134 pat[3].w = pc98_egc_src[3].w; 01135 } 01136 else { 01137 pat[0].w = pc98_gdc_tiles[0].w; 01138 pat[1].w = pc98_gdc_tiles[1].w; 01139 pat[2].w = pc98_gdc_tiles[2].w; 01140 pat[3].w = pc98_gdc_tiles[3].w; 01141 } 01142 break; 01143 } 01144 01145 egc_fetch_planar<uint16_t>(/*&*/dst,vramoff); 01146 01147 pc98_egc_data[0].w = 0; 01148 pc98_egc_data[1].w = 0; 01149 pc98_egc_data[2].w = 0; 01150 pc98_egc_data[3].w = 0; 01151 01152 if (ope & 0x80) { 01153 pc98_egc_data[0].w |= ( pat[0].w & pc98_egc_src[0].w & dst[0].w); 01154 pc98_egc_data[1].w |= ( pat[1].w & pc98_egc_src[1].w & dst[1].w); 01155 pc98_egc_data[2].w |= ( pat[2].w & pc98_egc_src[2].w & dst[2].w); 01156 pc98_egc_data[3].w |= ( pat[3].w & pc98_egc_src[3].w & dst[3].w); 01157 } 01158 if (ope & 0x40) { 01159 pc98_egc_data[0].w |= ((~pat[0].w) & pc98_egc_src[0].w & dst[0].w); 01160 pc98_egc_data[1].w |= ((~pat[1].w) & pc98_egc_src[1].w & dst[1].w); 01161 pc98_egc_data[2].w |= ((~pat[2].w) & pc98_egc_src[2].w & dst[2].w); 01162 pc98_egc_data[3].w |= ((~pat[3].w) & pc98_egc_src[3].w & dst[3].w); 01163 } 01164 if (ope & 0x20) { 01165 pc98_egc_data[0].w |= ( pat[0].w & pc98_egc_src[0].w & (~dst[0].w)); 01166 pc98_egc_data[1].w |= ( pat[1].w & pc98_egc_src[1].w & (~dst[1].w)); 01167 pc98_egc_data[2].w |= ( pat[2].w & pc98_egc_src[2].w & (~dst[2].w)); 01168 pc98_egc_data[3].w |= ( pat[3].w & pc98_egc_src[3].w & (~dst[3].w)); 01169 } 01170 if (ope & 0x10) { 01171 pc98_egc_data[0].w |= ((~pat[0].w) & pc98_egc_src[0].w & (~dst[0].w)); 01172 pc98_egc_data[1].w |= ((~pat[1].w) & pc98_egc_src[1].w & (~dst[1].w)); 01173 pc98_egc_data[2].w |= ((~pat[2].w) & pc98_egc_src[2].w & (~dst[2].w)); 01174 pc98_egc_data[3].w |= ((~pat[3].w) & pc98_egc_src[3].w & (~dst[3].w)); 01175 } 01176 if (ope & 0x08) { 01177 pc98_egc_data[0].w |= ( pat[0].w & (~pc98_egc_src[0].w) & dst[0].w); 01178 pc98_egc_data[1].w |= ( pat[1].w & (~pc98_egc_src[1].w) & dst[1].w); 01179 pc98_egc_data[2].w |= ( pat[2].w & (~pc98_egc_src[2].w) & dst[2].w); 01180 pc98_egc_data[3].w |= ( pat[3].w & (~pc98_egc_src[3].w) & dst[3].w); 01181 } 01182 if (ope & 0x04) { 01183 pc98_egc_data[0].w |= ((~pat[0].w) & (~pc98_egc_src[0].w) & dst[0].w); 01184 pc98_egc_data[1].w |= ((~pat[1].w) & (~pc98_egc_src[1].w) & dst[1].w); 01185 pc98_egc_data[2].w |= ((~pat[2].w) & (~pc98_egc_src[2].w) & dst[2].w); 01186 pc98_egc_data[3].w |= ((~pat[3].w) & (~pc98_egc_src[3].w) & dst[3].w); 01187 } 01188 if (ope & 0x02) { 01189 pc98_egc_data[0].w |= ( pat[0].w & (~pc98_egc_src[0].w) & (~dst[0].w)); 01190 pc98_egc_data[1].w |= ( pat[1].w & (~pc98_egc_src[1].w) & (~dst[1].w)); 01191 pc98_egc_data[2].w |= ( pat[2].w & (~pc98_egc_src[2].w) & (~dst[2].w)); 01192 pc98_egc_data[3].w |= ( pat[3].w & (~pc98_egc_src[3].w) & (~dst[3].w)); 01193 } 01194 if (ope & 0x01) { 01195 pc98_egc_data[0].w |= ((~pat[0].w) & (~pc98_egc_src[0].w) & (~dst[0].w)); 01196 pc98_egc_data[1].w |= ((~pat[1].w) & (~pc98_egc_src[1].w) & (~dst[1].w)); 01197 pc98_egc_data[2].w |= ((~pat[2].w) & (~pc98_egc_src[2].w) & (~dst[2].w)); 01198 pc98_egc_data[3].w |= ((~pat[3].w) & (~pc98_egc_src[3].w) & (~dst[3].w)); 01199 } 01200 01201 return pc98_egc_data; 01202 } 01203 01204 static const PC98_OPEFN pc98_egc_opfn[256] = { 01205 ope_00, ope_xx, ope_xx, ope_np, ope_xx, ope_nd, ope_xx, ope_xx, 01206 ope_xx, ope_xx, ope_nd, ope_xx, ope_np, ope_xx, ope_xx, ope_0f, 01207 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01208 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01209 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01210 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01211 ope_np, ope_xx, ope_xx, ope_np, ope_xx, ope_xx, ope_xx, ope_xx, 01212 ope_xx, ope_xx, ope_xx, ope_xx, ope_np, ope_xx, ope_xx, ope_np, 01213 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01214 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01215 ope_nd, ope_xx, ope_xx, ope_xx, ope_xx, ope_nd, ope_xx, ope_xx, 01216 ope_xx, ope_xx, ope_nd, ope_xx, ope_xx, ope_xx, ope_xx, ope_nd, 01217 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_gg, ope_xx, 01218 ope_xx, ope_xx, ope_xx, ope_xx, ope_gg, ope_xx, ope_xx, ope_xx, 01219 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01220 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01221 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01222 ope_gg, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01223 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01224 ope_xx, ope_xx, ope_xx, ope_xx, ope_gg, ope_xx, ope_xx, ope_xx, 01225 ope_nd, ope_xx, ope_xx, ope_xx, ope_xx, ope_nd, ope_xx, ope_xx, 01226 ope_xx, ope_xx, ope_nd, ope_xx, ope_gg, ope_xx, ope_xx, ope_nd, 01227 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01228 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01229 ope_c0, ope_xx, ope_xx, ope_np, ope_xx, ope_xx, ope_xx, ope_xx, 01230 ope_gg, ope_xx, ope_gg, ope_xx, ope_np, ope_gg, ope_xx, ope_np, 01231 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01232 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01233 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, 01234 ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_xx, ope_gg, ope_xx, 01235 ope_f0, ope_xx, ope_xx, ope_np, ope_xx, ope_nd, ope_xx, ope_xx, 01236 ope_xx, ope_xx, ope_nd, ope_xx, ope_fc, ope_xx, ope_xx, ope_ff}; 01237 01238 template <class AWT> static egc_quad &egc_ope(const PhysPt vramoff, const AWT val) { 01239 *((uint16_t*)pc98_egc_maskef) = *((uint16_t*)pc98_egc_mask); 01240 01241 /* 4A4h 01242 * bits [12:11] = light source 01243 * 11 = invalid 01244 * 10 = write the contents of the palette register 01245 * 01 = write the result of the raster operation 01246 * 00 = write CPU data 01247 * 01248 * 4A2h 01249 * bits [14:13] = foreground, background color 01250 * 11 = invalid 01251 * 10 = foreground color 01252 * 01 = background color 01253 * 00 = pattern register 01254 */ 01255 switch (pc98_egc_lightsource) { 01256 case 1: /* 0x0800 */ 01257 if (pc98_egc_shiftinput) { 01258 pc98_egc_shift.input<AWT>( 01259 val, 01260 val, 01261 val, 01262 val, 01263 vramoff&1); 01264 01265 pc98_egc_shift.output<AWT>( 01266 *((AWT*)(pc98_egc_src[0].b+(vramoff&1))), 01267 *((AWT*)(pc98_egc_src[1].b+(vramoff&1))), 01268 *((AWT*)(pc98_egc_src[2].b+(vramoff&1))), 01269 *((AWT*)(pc98_egc_src[3].b+(vramoff&1))), 01270 vramoff&1); 01271 } 01272 01273 *((uint16_t*)pc98_egc_maskef) &= *((uint16_t*)pc98_egc_srcmask); 01274 return pc98_egc_opfn[pc98_egc_rop](pc98_egc_rop, vramoff & (~1U)); 01275 case 2: /* 0x1000 */ 01276 if (pc98_egc_fgc == 1) 01277 return pc98_egc_bgcm; 01278 else if (pc98_egc_fgc == 2) 01279 return pc98_egc_fgcm; 01280 01281 if (pc98_egc_shiftinput) { 01282 pc98_egc_shift.input<AWT>( 01283 val, 01284 val, 01285 val, 01286 val, 01287 vramoff&1); 01288 01289 pc98_egc_shift.output<AWT>( 01290 *((AWT*)(pc98_egc_src[0].b+(vramoff&1))), 01291 *((AWT*)(pc98_egc_src[1].b+(vramoff&1))), 01292 *((AWT*)(pc98_egc_src[2].b+(vramoff&1))), 01293 *((AWT*)(pc98_egc_src[3].b+(vramoff&1))), 01294 vramoff&1); 01295 } 01296 01297 *((uint16_t*)pc98_egc_maskef) &= *((uint16_t*)pc98_egc_srcmask); 01298 return pc98_egc_src; 01299 default: { 01300 uint16_t tmp = (uint16_t)val; 01301 01302 if (sizeof(AWT) < 2) { 01303 tmp &= 0xFFU; 01304 tmp |= tmp << 8U; 01305 } 01306 01307 pc98_egc_data[0].w = tmp; 01308 pc98_egc_data[1].w = tmp; 01309 pc98_egc_data[2].w = tmp; 01310 pc98_egc_data[3].w = tmp; 01311 } break; 01312 } 01313 01314 return pc98_egc_data; 01315 } 01316 01317 unsigned char pc98_mem_msw_m[8] = {0}; 01318 01319 void pc98_msw3_set_ramsize(const unsigned char b) { 01320 pc98_mem_msw_m[2/*MSW3*/] = b; 01321 } 01322 01323 unsigned char pc98_mem_msw(unsigned char which) { 01324 return pc98_mem_msw_m[which&7]; 01325 } 01326 01327 void pc98_mem_msw_write(unsigned char which,unsigned char val) { 01328 LOG_MSG("WARNING: PC-98 NVRAM write to 0x%x value 0x%x, not implemented yet",which,val); 01329 // TODO: Add code to write NVRAM. 01330 // According to documentation writing is only enabled if a register is written elsewhere to allow it. 01331 } 01332 01333 /* The NEC display is documented to have: 01334 * 01335 * A0000-A3FFF T-RAM (text) (8KB WORDs) 01336 * A0000-A1FFF Characters (4KB WORDs) 01337 * A2000-A3FFF Attributes (4KB WORDs). For each 16-bit WORD only the lower 8 bits are read/writeable. 01338 * A4000-A5FFF Unknown ?? (4KB WORDs) 01339 * A6000-A7FFF Not present (4KB WORDs) 01340 * A8000-BFFFF G-RAM (graphics) (96KB) 01341 * 01342 * T-RAM character display RAM is 16-bits per character. 01343 * ASCII text has upper 8 bits zero. 01344 * SHIFT-JIS doublewide characters use the upper byte for non-ASCII. */ 01345 01346 /* A0000-A3FFF text character + attribute RAM */ 01347 /* 01348 * 0xA3FE2 MSW1 01349 * 0xA3FE6 MSW2 01350 * 0xA3FEA MSW3 01351 * 0xA3FEE MSW4 01352 * 0xA3FF2 MSW5 01353 * 0xA3FF6 MSW6 01354 * 0xA3FFA MSW7 01355 * 0xA3FFE MSW8 01356 * 01357 * TODO: Study real hardware to determine what the bytes between the NVRAM bytes are. 01358 * Are they repeats of the MSW bytes, some other value, or just 0xFF? 01359 */ 01360 class VGA_PC98_TEXT_PageHandler : public PageHandler { 01361 public: 01362 VGA_PC98_TEXT_PageHandler() : PageHandler(PFLAG_NOCODE) {} 01363 Bit8u readb(PhysPt addr) { 01364 addr &= 0x3FFFu; 01365 01366 if (addr >= 0x3FE0u) 01367 return pc98_mem_msw((addr >> 2u) & 7u); 01368 else if ((addr & 0x2001u) == 0x2001u) 01369 return (Bit8u)(~0u); /* Odd bytes of attribute RAM do not exist, apparently */ 01370 01371 return VRAM98_TEXT[addr]; 01372 } 01373 void writeb(PhysPt addr,Bit8u val) { 01374 addr &= 0x3FFFu; 01375 01376 if (addr >= 0x3FE0u) 01377 return pc98_mem_msw_write((addr >> 2u) & 7u,(unsigned char)val); 01378 else if ((addr & 0x2001u) == 0x2001u) 01379 return; /* Odd bytes of attribute RAM do not exist, apparently */ 01380 01381 VRAM98_TEXT[addr] = (unsigned char)val; 01382 } 01383 }; 01384 01385 extern uint16_t a1_font_load_addr; 01386 01387 /* A4000-A4FFF character generator memory-mapped I/O */ 01388 /* 0xA4000-0xA4FFF is word-sized access to the character generator. 01389 * 01390 * Some games, though not many, appear to prefer this memory-mapped I/O 01391 * rather than the I/O ports. 01392 * 01393 * This fixes: 01394 * - Eve Burst Error 01395 * 01396 * Also noted: Disassembling the CG functions of the BIOS on an actual 01397 * PC9821 laptop reveals that the BIOS also uses this method, 01398 * using REP MOVSW 01399 * 01400 * Also noted: On real hardware, A4000-A4FFF seems to latch to the CG. 01401 * A5000-A5FFF seems to latch to nothing. */ 01402 01403 /* according to real hardware, memory address does not affect char offset (port 0xA5) */ 01404 class VGA_PC98_CG_PageHandler : public PageHandler { 01405 public: 01406 VGA_PC98_CG_PageHandler() : PageHandler(PFLAG_NOCODE) {} 01407 Bit8u readb(PhysPt addr) { 01408 return pc98_font_char_read(a1_font_load_addr,(addr >> 1) & 0xF,addr & 1); 01409 } 01410 void writeb(PhysPt addr,Bit8u val) { 01411 pc98_font_char_write(a1_font_load_addr,(addr >> 1) & 0xF,addr & 1,val); 01412 } 01413 }; 01414 01415 /* 256-color control registers, memory mapped I/O */ 01416 class VGA_PC98_256MMIO_PageHandler : public PageHandler { 01417 public: 01418 VGA_PC98_256MMIO_PageHandler() : PageHandler(PFLAG_NOCODE) {} 01419 Bit8u readb(PhysPt addr) { 01420 return pc98_pegc_mmio_read(addr & 0x7FFFu); 01421 } 01422 void writeb(PhysPt addr,Bit8u val) { 01423 pc98_pegc_mmio_write(addr & 0x7FFFu,val); 01424 } 01425 }; 01426 01427 // A8000h-B7FFFh is 256-color planar (????) 01428 // I don't THINK the bank switching registers have any effect. Not sure. 01429 // However it makes sense to make it a 64KB region because 8 planes x 64KB = 512KB of RAM. Right? 01430 // By the way real PEGC hardware seems to prefer WORD (16-bit) sized read/write aligned on WORD boundaries. 01431 // In fact Windows 3.1's 256-color driver never uses byte-sized read/write in this planar mode. 01432 class VGA_PC98_256Planar_PageHandler : public PageHandler { 01433 public: 01434 VGA_PC98_256Planar_PageHandler() : PageHandler(PFLAG_NOCODE) {} 01435 Bit8u readb(PhysPt addr) { 01436 (void)addr; 01437 01438 // LOG_MSG("PEGC 256-color planar warning: Readb from %lxh",(unsigned long)addr); 01439 return (Bit8u)(~0); 01440 } 01441 void writeb(PhysPt addr,Bit8u val) { 01442 (void)addr; 01443 (void)val; 01444 01445 // LOG_MSG("PEGC 256-color planar warning: Writeb to %lxh val %02xh",(unsigned long)addr,(unsigned int)val); 01446 } 01447 Bit16u readw(PhysPt addr) { 01448 (void)addr; 01449 01450 // LOG_MSG("PEGC 256-color planar warning: Readw from %lxh",(unsigned long)addr); 01451 return (Bit16u)(~0); 01452 } 01453 void writew(PhysPt addr,Bit16u val) { 01454 (void)addr; 01455 (void)val; 01456 01457 // LOG_MSG("PEGC 256-color planar warning: Writew to %lxh val %04xh",(unsigned long)addr,(unsigned int)val); 01458 } 01459 }; 01460 01461 // A8000h is bank 0 01462 // B0000h is bank 1 01463 template <const unsigned int bank> class VGA_PC98_256BANK_PageHandler : public PageHandler { 01464 public: 01465 VGA_PC98_256BANK_PageHandler() : PageHandler(PFLAG_NOCODE) {} 01466 Bit8u readb(PhysPt addr) { 01467 return pc98_vram_256bank_from_window(bank)[addr & 0x7FFFu]; 01468 } 01469 void writeb(PhysPt addr,Bit8u val) { 01470 pc98_vram_256bank_from_window(bank)[addr & 0x7FFFu] = val; 01471 } 01472 }; 01473 01474 namespace pc98pgmio { 01475 01476 template <class AWT> static inline void check_align(const PhysPt addr) { 01477 #if 0 01478 /* DEBUG: address must be aligned to datatype. 01479 * Code that calls us must enforce that or subdivide 01480 * to a small datatype that can follow this rule. */ 01481 PhysPt chk = (1UL << (sizeof(AWT) - 1)) - 1; 01482 /* uint8_t: chk = 0 01483 * uint16_t: chk = 1 01484 * TODO: Do you suppose later generation PC-9821's supported DWORD size bitplane transfers? 01485 * Or did NEC just give up on anything past 16-bit and focus on the SVGA side of things? */ 01486 assert((addr&chk) == 0); 01487 #else 01488 (void)addr; 01489 #endif 01490 } 01491 01492 } 01493 01494 class VGA_PC98_PageHandler : public PageHandler { 01495 public: 01496 VGA_PC98_PageHandler() : PageHandler(PFLAG_NOCODE) {} 01497 01498 template <class AWT> static inline AWT mode8_r(const unsigned int plane,const PhysPt vramoff) { 01499 AWT r,b; 01500 01501 b = *((AWT*)(pc98_pgraph_current_cpu_page + vramoff)); 01502 r = b ^ *((AWT*)pc98_gdc_tiles[plane].b); 01503 01504 return r; 01505 } 01506 01507 template <class AWT> static inline void mode8_w(const unsigned int plane,const PhysPt vramoff) { 01508 AWT tb; 01509 01510 /* Neko Project II code suggests that the first byte is repeated. */ 01511 if (sizeof(AWT) > 1) 01512 tb = pc98_gdc_tiles[plane].b[0] | (pc98_gdc_tiles[plane].b[0] << 8u); 01513 else 01514 tb = pc98_gdc_tiles[plane].b[0]; 01515 01516 *((AWT*)(pc98_pgraph_current_cpu_page + vramoff)) = tb; 01517 } 01518 01519 template <class AWT> static inline void modeC_w(const unsigned int plane,const PhysPt vramoff,const AWT mask,const AWT val) { 01520 AWT t,tb; 01521 01522 /* Neko Project II code suggests that the first byte is repeated. */ 01523 if (sizeof(AWT) > 1) 01524 tb = pc98_gdc_tiles[plane].b[0] | (pc98_gdc_tiles[plane].b[0] << 8u); 01525 else 01526 tb = pc98_gdc_tiles[plane].b[0]; 01527 01528 t = *((AWT*)(pc98_pgraph_current_cpu_page + vramoff)) & mask; 01529 t |= val & tb; 01530 *((AWT*)(pc98_pgraph_current_cpu_page + vramoff)) = t; 01531 } 01532 01533 template <class AWT> static inline AWT modeEGC_r(const PhysPt vramoff,const PhysPt fulloff) { 01534 /* assume: vramoff is even IF AWT is 16-bit wide */ 01535 *((AWT*)(pc98_egc_last_vram[0].b+(vramoff&1))) = *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(0))); 01536 *((AWT*)(pc98_egc_last_vram[1].b+(vramoff&1))) = *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(1))); 01537 *((AWT*)(pc98_egc_last_vram[2].b+(vramoff&1))) = *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(2))); 01538 *((AWT*)(pc98_egc_last_vram[3].b+(vramoff&1))) = *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(3))); 01539 01540 /* bits [10:10] = read source 01541 * 1 = shifter input is CPU write data 01542 * 0 = shifter input is VRAM data */ 01543 /* Neko Project II: if ((egc.ope & 0x0400) == 0) ... */ 01544 if (!pc98_egc_shiftinput) { 01545 pc98_egc_shift.input<AWT>( 01546 *((AWT*)(pc98_egc_last_vram[0].b+(vramoff&1))), 01547 *((AWT*)(pc98_egc_last_vram[1].b+(vramoff&1))), 01548 *((AWT*)(pc98_egc_last_vram[2].b+(vramoff&1))), 01549 *((AWT*)(pc98_egc_last_vram[3].b+(vramoff&1))), 01550 vramoff&1); 01551 01552 pc98_egc_shift.output<AWT>( 01553 *((AWT*)(pc98_egc_src[0].b+(vramoff&1))), 01554 *((AWT*)(pc98_egc_src[1].b+(vramoff&1))), 01555 *((AWT*)(pc98_egc_src[2].b+(vramoff&1))), 01556 *((AWT*)(pc98_egc_src[3].b+(vramoff&1))), 01557 vramoff&1); 01558 } 01559 01560 /* 0x4A4: 01561 * ... 01562 * bits [9:8] = register load (pc98_egc_regload[1:0]) 01563 * 11 = invalid 01564 * 10 = load VRAM data before writing on VRAM write 01565 * 01 = load VRAM data into pattern/tile register on VRAM read 01566 * 00 = Do not change pattern/tile register 01567 * ... 01568 * 01569 * pc98_egc_regload = (val >> 8) & 3; 01570 */ 01571 /* Neko Project II: if ((egc.ope & 0x0300) == 0x0100) ... */ 01572 if (pc98_egc_regload & 1) { /* load VRAM data into pattern/tile... (or INVALID) */ 01573 *((AWT*)(pc98_gdc_tiles[0].b+(vramoff&1))) = *((AWT*)(pc98_egc_last_vram[0].b+(vramoff&1))); 01574 *((AWT*)(pc98_gdc_tiles[1].b+(vramoff&1))) = *((AWT*)(pc98_egc_last_vram[1].b+(vramoff&1))); 01575 *((AWT*)(pc98_gdc_tiles[2].b+(vramoff&1))) = *((AWT*)(pc98_egc_last_vram[2].b+(vramoff&1))); 01576 *((AWT*)(pc98_gdc_tiles[3].b+(vramoff&1))) = *((AWT*)(pc98_egc_last_vram[3].b+(vramoff&1))); 01577 } 01578 01579 /* 0x4A4: 01580 * bits [13:13] = 0=compare lead plane 1=don't 01581 * 01582 * bits [10:10] = read source 01583 * 1 = shifter input is CPU write data 01584 * 0 = shifter input is VRAM data */ 01585 if (pc98_egc_compare_lead) { 01586 if (!pc98_egc_shiftinput) 01587 return *((AWT*)(pc98_egc_src[pc98_egc_lead_plane&3].b)); 01588 else 01589 return *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+((pc98_egc_lead_plane&3)*PC98_VRAM_BITPLANE_SIZE))); 01590 } 01591 01592 return *((AWT*)(pc98_pgraph_current_cpu_page+fulloff)); 01593 } 01594 01595 template <class AWT> static inline void modeEGC_w(const PhysPt vramoff,const AWT val) { 01596 /* assume: vramoff is even IF AWT is 16-bit wide */ 01597 01598 /* 0x4A4: 01599 * ... 01600 * bits [9:8] = register load (pc98_egc_regload[1:0]) 01601 * 11 = invalid 01602 * 10 = load VRAM data before writing on VRAM write 01603 * 01 = load VRAM data into pattern/tile register on VRAM read 01604 * 00 = Do not change pattern/tile register 01605 * ... 01606 * pc98_egc_regload = (val >> 8) & 3; 01607 */ 01608 /* Neko Project II: if ((egc.ope & 0x0300) == 0x0200) ... */ 01609 if (pc98_egc_regload & 2) { /* load VRAM data before writing on VRAM write (or INVALID) */ 01610 *((AWT*)(pc98_gdc_tiles[0].b+(vramoff&1))) = *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(0))); 01611 *((AWT*)(pc98_gdc_tiles[1].b+(vramoff&1))) = *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(1))); 01612 *((AWT*)(pc98_gdc_tiles[2].b+(vramoff&1))) = *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(2))); 01613 *((AWT*)(pc98_gdc_tiles[3].b+(vramoff&1))) = *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(3))); 01614 } 01615 01616 egc_quad &ropdata = egc_ope<AWT>(vramoff, val); 01617 01618 const AWT accmask = *((AWT*)(pc98_egc_maskef+(vramoff&1))); 01619 01620 if (accmask != 0) { 01621 if (!(pc98_egc_access & 1)) { 01622 *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(0))) &= ~accmask; 01623 *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(0))) |= accmask & *((AWT*)(ropdata[0].b+(vramoff&1))); 01624 } 01625 if (!(pc98_egc_access & 2)) { 01626 *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(1))) &= ~accmask; 01627 *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(1))) |= accmask & *((AWT*)(ropdata[1].b+(vramoff&1))); 01628 } 01629 if (!(pc98_egc_access & 4)) { 01630 *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(2))) &= ~accmask; 01631 *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(2))) |= accmask & *((AWT*)(ropdata[2].b+(vramoff&1))); 01632 } 01633 if (!(pc98_egc_access & 8)) { 01634 *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(3))) &= ~accmask; 01635 *((AWT*)(pc98_pgraph_current_cpu_page+vramoff+pc98_pgram_bitplane_offset(3))) |= accmask & *((AWT*)(ropdata[3].b+(vramoff&1))); 01636 } 01637 } 01638 } 01639 01640 template <class AWT> AWT readc(PhysPt addr) { 01641 pc98pgmio::check_align<AWT>(addr); 01642 01643 unsigned int plane = ((addr >> 15u) + 3u) & 3u; 01644 addr &= 0x7FFF; 01645 01646 /* reminder: 01647 * 01648 * bit 1: VOPBIT_EGC 01649 * bit 0: VOPBIT_ACCESS 01650 * From GRGC bits: 01651 * bit 3: VOPBIT_GRCG 1=GRGC active 0=GRGC invalid (from bit 7) 01652 * bit 2: VOPBIT_GRCG 1=Read/Modify/Write when writing 0=TCR mode at read, TDW mode at write (from bit 6) */ 01653 switch (pc98_gdc_vramop & 0xF) { 01654 case 0x00: 01655 case 0x01: 01656 case 0x02: 01657 case 0x03: 01658 case 0x04: 01659 case 0x05: 01660 case 0x06: 01661 case 0x07: 01662 case 0x0C: 01663 case 0x0D: 01664 return *((AWT*)(pc98_pgraph_current_cpu_page+addr+pc98_pgram_bitplane_offset(plane))); 01665 case 0x08: /* TCR/TDW */ 01666 case 0x09: 01667 { 01668 AWT r = 0; 01669 01670 /* this reads multiple bitplanes at once */ 01671 if (!(pc98_gdc_modereg & 1)) // blue channel 01672 r |= mode8_r<AWT>(/*plane*/0,addr + pc98_pgram_bitplane_offset(0)); 01673 01674 if (!(pc98_gdc_modereg & 2)) // red channel 01675 r |= mode8_r<AWT>(/*plane*/1,addr + pc98_pgram_bitplane_offset(1)); 01676 01677 if (!(pc98_gdc_modereg & 4)) // green channel 01678 r |= mode8_r<AWT>(/*plane*/2,addr + pc98_pgram_bitplane_offset(2)); 01679 01680 if (!(pc98_gdc_modereg & 8)) // extended channel 01681 r |= mode8_r<AWT>(/*plane*/3,addr + pc98_pgram_bitplane_offset(3)); 01682 01683 /* NTS: Apparently returning this value correctly really matters to the 01684 * sprite engine in "Edge", else visual errors occur. */ 01685 return ~r; 01686 } 01687 case 0x0A: /* EGC read */ 01688 case 0x0B: 01689 case 0x0E: 01690 case 0x0F: 01691 /* this reads multiple bitplanes at once */ 01692 return modeEGC_r<AWT>(addr,addr); 01693 default: /* should not happen */ 01694 break; 01695 } 01696 01697 return (AWT)(~0ull); 01698 } 01699 01700 template <class AWT> void writec(PhysPt addr,AWT val) { 01701 pc98pgmio::check_align<AWT>(addr); 01702 01703 unsigned int plane = ((addr >> 15u) + 3u) & 3u; 01704 addr &= 0x7FFF; 01705 01706 /* reminder: 01707 * 01708 * bit 1: VOPBIT_EGC 01709 * bit 0: VOPBIT_ACCESS 01710 * From GRGC bits: 01711 * bit 3: VOPBIT_GRCG 1=GRGC active 0=GRGC invalid (from bit 7) 01712 * bit 2: VOPBIT_GRCG 1=Read/Modify/Write when writing 0=TCR mode at read, TDW mode at write (from bit 6) */ 01713 switch (pc98_gdc_vramop & 0xF) { 01714 case 0x00: 01715 case 0x01: 01716 case 0x02: 01717 case 0x03: 01718 case 0x04: 01719 case 0x05: 01720 case 0x06: 01721 case 0x07: 01722 *((AWT*)(pc98_pgraph_current_cpu_page+addr+pc98_pgram_bitplane_offset(plane))) = val; 01723 break; 01724 case 0x08: /* TCR/TDW write tile data, no masking */ 01725 case 0x09: 01726 { 01727 /* this writes to multiple bitplanes at once. 01728 * notice that the value written has no meaning, only the tile data and memory address. */ 01729 if (!(pc98_gdc_modereg & 1)) // blue channel 01730 mode8_w<AWT>(0/*plane*/,addr + pc98_pgram_bitplane_offset(0)); 01731 01732 if (!(pc98_gdc_modereg & 2)) // red channel 01733 mode8_w<AWT>(1/*plane*/,addr + pc98_pgram_bitplane_offset(1)); 01734 01735 if (!(pc98_gdc_modereg & 4)) // green channel 01736 mode8_w<AWT>(2/*plane*/,addr + pc98_pgram_bitplane_offset(2)); 01737 01738 if (!(pc98_gdc_modereg & 8)) // extended channel 01739 mode8_w<AWT>(3/*plane*/,addr + pc98_pgram_bitplane_offset(3)); 01740 } 01741 break; 01742 case 0x0C: /* read/modify/write from tile with masking */ 01743 case 0x0D: /* a lot of PC-98 games seem to rely on this for sprite rendering */ 01744 { 01745 const AWT mask = ~val; 01746 01747 /* this writes to multiple bitplanes at once */ 01748 if (!(pc98_gdc_modereg & 1)) // blue channel 01749 modeC_w<AWT>(0/*plane*/,addr + pc98_pgram_bitplane_offset(0),mask,val); 01750 01751 if (!(pc98_gdc_modereg & 2)) // red channel 01752 modeC_w<AWT>(1/*plane*/,addr + pc98_pgram_bitplane_offset(1),mask,val); 01753 01754 if (!(pc98_gdc_modereg & 4)) // green channel 01755 modeC_w<AWT>(2/*plane*/,addr + pc98_pgram_bitplane_offset(2),mask,val); 01756 01757 if (!(pc98_gdc_modereg & 8)) // extended channel 01758 modeC_w<AWT>(3/*plane*/,addr + pc98_pgram_bitplane_offset(3),mask,val); 01759 } 01760 break; 01761 case 0x0A: /* EGC write */ 01762 case 0x0B: 01763 case 0x0E: 01764 case 0x0F: 01765 /* this reads multiple bitplanes at once */ 01766 modeEGC_w<AWT>(addr,val); 01767 break; 01768 default: /* Should not happen */ 01769 break; 01770 } 01771 } 01772 01773 /* byte-wise */ 01774 Bit8u readb(PhysPt addr) { 01775 return readc<uint8_t>( PAGING_GetPhysicalAddress(addr) ); 01776 } 01777 void writeb(PhysPt addr,Bit8u val) { 01778 writec<uint8_t>( PAGING_GetPhysicalAddress(addr), val ); 01779 } 01780 01781 /* word-wise. 01782 * in the style of the 8086, non-word-aligned I/O is split into byte I/O */ 01783 Bit16u readw(PhysPt addr) { 01784 addr = PAGING_GetPhysicalAddress(addr); 01785 if (!(addr & 1)) /* if WORD aligned */ 01786 return readc<uint16_t>(addr); 01787 else { 01788 return (unsigned int)readc<uint8_t>(addr+0U) + 01789 ((unsigned int)readc<uint8_t>(addr+1U) << 8u); 01790 } 01791 } 01792 void writew(PhysPt addr,Bit16u val) { 01793 addr = PAGING_GetPhysicalAddress(addr); 01794 if (!(addr & 1)) /* if WORD aligned */ 01795 writec<uint16_t>(addr,val); 01796 else { 01797 writec<uint8_t>(addr+0,(uint8_t)val); 01798 writec<uint8_t>(addr+1,(uint8_t)(val >> 8U)); 01799 } 01800 } 01801 }; 01802 01803 class VGA_PC98_LFB_Handler : public PageHandler { 01804 public: 01805 VGA_PC98_LFB_Handler() : PageHandler(PFLAG_READABLE|PFLAG_WRITEABLE|PFLAG_NOCODE) {} 01806 HostPt GetHostReadPt(Bitu phys_page) { 01807 return &vga.mem.linear[(phys_page&0x7F)*4096 + PC98_VRAM_GRAPHICS_OFFSET]; /* 512KB mapping */ 01808 } 01809 HostPt GetHostWritePt(Bitu phys_page) { 01810 return &vga.mem.linear[(phys_page&0x7F)*4096 + PC98_VRAM_GRAPHICS_OFFSET]; /* 512KB mapping */ 01811 } 01812 }; 01813 01814 class VGA_Map_Handler : public PageHandler { 01815 public: 01816 VGA_Map_Handler() : PageHandler(PFLAG_READABLE|PFLAG_WRITEABLE|PFLAG_NOCODE) {} 01817 HostPt GetHostReadPt(Bitu phys_page) { 01818 phys_page-=vgapages.base; 01819 return &vga.mem.linear[CHECKED3(vga.svga.bank_read_full+phys_page*4096)]; 01820 } 01821 HostPt GetHostWritePt(Bitu phys_page) { 01822 phys_page-=vgapages.base; 01823 return &vga.mem.linear[CHECKED3(vga.svga.bank_write_full+phys_page*4096)]; 01824 } 01825 }; 01826 01827 class VGA_Slow_CGA_Handler : public PageHandler { 01828 public: 01829 VGA_Slow_CGA_Handler() : PageHandler(PFLAG_NOCODE) {} 01830 void delay() { 01831 Bits delaycyc = (Bits)(CPU_CycleMax/((cpu_cycles_count_t)(1024/2.80))); 01832 if(GCC_UNLIKELY(CPU_Cycles < 3*delaycyc)) delaycyc=0; 01833 CPU_Cycles -= delaycyc; 01834 CPU_IODelayRemoved += delaycyc; 01835 } 01836 01837 Bit8u readb(PhysPt addr) { 01838 delay(); 01839 return vga.tandy.mem_base[(addr - 0xb8000) & 0x3FFF]; 01840 } 01841 void writeb(PhysPt addr,Bit8u val){ 01842 delay(); 01843 vga.tandy.mem_base[(addr - 0xb8000) & 0x3FFF] = val; 01844 } 01845 01846 }; 01847 01848 class VGA_LFB_Handler : public PageHandler { 01849 public: 01850 VGA_LFB_Handler() : PageHandler(PFLAG_READABLE|PFLAG_WRITEABLE|PFLAG_NOCODE) {} 01851 HostPt GetHostReadPt( Bitu phys_page ) { 01852 phys_page -= vga.lfb.page; 01853 phys_page &= (vga.mem.memsize >> 12) - 1; 01854 return &vga.mem.linear[CHECKED3(phys_page * 4096)]; 01855 } 01856 HostPt GetHostWritePt( Bitu phys_page ) { 01857 return GetHostReadPt( phys_page ); 01858 } 01859 }; 01860 01861 extern void XGA_Write(Bitu port, Bitu val, Bitu len); 01862 extern Bitu XGA_Read(Bitu port, Bitu len); 01863 01864 class VGA_MMIO_Handler : public PageHandler { 01865 public: 01866 VGA_MMIO_Handler() : PageHandler(PFLAG_NOCODE) {} 01867 void writeb(PhysPt addr,Bit8u val) { 01868 VGAMEM_USEC_write_delay(); 01869 Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff; 01870 XGA_Write(port, val, 1); 01871 } 01872 void writew(PhysPt addr,Bit16u val) { 01873 VGAMEM_USEC_write_delay(); 01874 Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff; 01875 XGA_Write(port, val, 2); 01876 } 01877 void writed(PhysPt addr,Bit32u val) { 01878 VGAMEM_USEC_write_delay(); 01879 Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff; 01880 XGA_Write(port, val, 4); 01881 } 01882 01883 Bit8u readb(PhysPt addr) { 01884 VGAMEM_USEC_read_delay(); 01885 Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff; 01886 return (Bit8u)XGA_Read(port, 1); 01887 } 01888 Bit16u readw(PhysPt addr) { 01889 VGAMEM_USEC_read_delay(); 01890 Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff; 01891 return (Bit16u)XGA_Read(port, 2); 01892 } 01893 Bit32u readd(PhysPt addr) { 01894 VGAMEM_USEC_read_delay(); 01895 Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff; 01896 return (Bit32u)XGA_Read(port, 4); 01897 } 01898 }; 01899 01900 class VGA_TANDY_PageHandler : public PageHandler { 01901 public: 01902 VGA_TANDY_PageHandler() : PageHandler(PFLAG_READABLE|PFLAG_WRITEABLE) {} 01903 HostPt GetHostReadPt(Bitu phys_page) { 01904 // Odd banks are limited to 16kB and repeated 01905 if (vga.tandy.mem_bank & 1) 01906 phys_page&=0x03; 01907 else 01908 phys_page&=0x07; 01909 return vga.tandy.mem_base + (phys_page * 4096); 01910 } 01911 HostPt GetHostWritePt(Bitu phys_page) { 01912 return GetHostReadPt( phys_page ); 01913 } 01914 }; 01915 01916 01917 class VGA_PCJR_Handler : public PageHandler { 01918 public: 01919 VGA_PCJR_Handler() : PageHandler(PFLAG_READABLE|PFLAG_WRITEABLE) {} 01920 HostPt GetHostReadPt(Bitu phys_page) { 01921 phys_page-=0xb8; 01922 // The 16kB map area is repeated in the 32kB range 01923 // On CGA CPU A14 is not decoded so it repeats there too 01924 phys_page&=0x03; 01925 return vga.tandy.mem_base + (phys_page * 4096); 01926 } 01927 HostPt GetHostWritePt(Bitu phys_page) { 01928 return GetHostReadPt( phys_page ); 01929 } 01930 }; 01931 01932 class VGA_AMS_Handler : public PageHandler { 01933 public: 01934 template< bool wrapping> 01935 void writeHandler(PhysPt start, Bit8u val) { 01936 vga.tandy.mem_base[ start ] = val; 01937 #ifdef DIJDIJD 01938 Bit32u data=ModeOperation(val); 01939 /* Update video memory and the pixel buffer */ 01940 VGA_Latch pixels; 01941 pixels.d=((Bit32u*)vga.mem.linear)[start]; 01942 pixels.d&=vga.config.full_not_map_mask; 01943 pixels.d|=(data & vga.config.full_map_mask); 01944 ((Bit32u*)vga.mem.linear)[start]=pixels.d; 01945 Bit8u * write_pixels=&vga.mem.linear[VGA_CACHE_OFFSET+(start<<3)]; 01946 01947 Bit32u colors0_3, colors4_7; 01948 VGA_Latch temp;temp.d=(pixels.d>>4) & 0x0f0f0f0f; 01949 colors0_3 = 01950 Expand16Table[0][temp.b[0]] | 01951 Expand16Table[1][temp.b[1]] | 01952 Expand16Table[2][temp.b[2]] | 01953 Expand16Table[3][temp.b[3]]; 01954 *(Bit32u *)write_pixels=colors0_3; 01955 temp.d=pixels.d & 0x0f0f0f0f; 01956 colors4_7 = 01957 Expand16Table[0][temp.b[0]] | 01958 Expand16Table[1][temp.b[1]] | 01959 Expand16Table[2][temp.b[2]] | 01960 Expand16Table[3][temp.b[3]]; 01961 *(Bit32u *)(write_pixels+4)=colors4_7; 01962 if (wrapping && GCC_UNLIKELY( start < 512)) { 01963 *(Bit32u *)(write_pixels+512*1024)=colors0_3; 01964 *(Bit32u *)(write_pixels+512*1024+4)=colors4_7; 01965 } 01966 #endif 01967 } 01968 // template< bool wrapping> 01969 Bit8u readHandler(PhysPt start) { 01970 return vga.tandy.mem_base[ start ]; 01971 } 01972 01973 public: 01974 VGA_AMS_Handler() { 01975 //flags=PFLAG_READABLE|PFLAG_WRITEABLE; 01976 flags=PFLAG_NOCODE; 01977 } 01978 inline PhysPt wrAddr( PhysPt addr ) 01979 { 01980 if( vga.mode != M_AMSTRAD ) 01981 { 01982 addr -= 0xb8000; 01983 PhysPt phys_page = addr >> 12; 01984 //test for a unaliged bank, then replicate 2x16kb 01985 if (vga.tandy.mem_bank & 1) 01986 phys_page&=0x03; 01987 return ( phys_page * 4096 ) + ( addr & 0x0FFF ); 01988 } 01989 return ( (PAGING_GetPhysicalAddress(addr) & 0xffff) - 0x8000 ) & ( 32*1024-1 ); 01990 } 01991 01992 void writeb(PhysPt addr,Bit8u val) { 01993 VGAMEM_USEC_write_delay(); 01994 addr = wrAddr( addr ); 01995 Bitu plane = vga.mode==M_AMSTRAD ? vga.amstrad.write_plane : 0x01; // 0x0F? 01996 if( plane & 0x08 ) writeHandler<false>(addr+49152,(Bit8u)(val >> 0)); 01997 if( plane & 0x04 ) writeHandler<false>(addr+32768,(Bit8u)(val >> 0)); 01998 if( plane & 0x02 ) writeHandler<false>(addr+16384,(Bit8u)(val >> 0)); 01999 if( plane & 0x01 ) writeHandler<false>(addr+0,(Bit8u)(val >> 0)); 02000 } 02001 void writew(PhysPt addr,Bit16u val) { 02002 VGAMEM_USEC_write_delay(); 02003 addr = wrAddr( addr ); 02004 Bitu plane = vga.mode==M_AMSTRAD ? vga.amstrad.write_plane : 0x01; // 0x0F? 02005 if( plane & 0x01 ) 02006 { 02007 writeHandler<false>(addr+0,(Bit8u)(val >> 0)); 02008 writeHandler<false>(addr+1,(Bit8u)(val >> 8)); 02009 } 02010 addr += 16384; 02011 if( plane & 0x02 ) 02012 { 02013 writeHandler<false>(addr+0,(Bit8u)(val >> 0)); 02014 writeHandler<false>(addr+1,(Bit8u)(val >> 8)); 02015 } 02016 addr += 16384; 02017 if( plane & 0x04 ) 02018 { 02019 writeHandler<false>(addr+0,(Bit8u)(val >> 0)); 02020 writeHandler<false>(addr+1,(Bit8u)(val >> 8)); 02021 } 02022 addr += 16384; 02023 if( plane & 0x08 ) 02024 { 02025 writeHandler<false>(addr+0,(Bit8u)(val >> 0)); 02026 writeHandler<false>(addr+1,(Bit8u)(val >> 8)); 02027 } 02028 02029 } 02030 void writed(PhysPt addr,Bit32u val) { 02031 VGAMEM_USEC_write_delay(); 02032 addr = wrAddr( addr ); 02033 Bitu plane = vga.mode==M_AMSTRAD ? vga.amstrad.write_plane : 0x01; // 0x0F? 02034 if( plane & 0x01 ) 02035 { 02036 writeHandler<false>(addr+0,(Bit8u)(val >> 0)); 02037 writeHandler<false>(addr+1,(Bit8u)(val >> 8)); 02038 writeHandler<false>(addr+2,(Bit8u)(val >> 16)); 02039 writeHandler<false>(addr+3,(Bit8u)(val >> 24)); 02040 } 02041 addr += 16384; 02042 if( plane & 0x02 ) 02043 { 02044 writeHandler<false>(addr+0,(Bit8u)(val >> 0)); 02045 writeHandler<false>(addr+1,(Bit8u)(val >> 8)); 02046 writeHandler<false>(addr+2,(Bit8u)(val >> 16)); 02047 writeHandler<false>(addr+3,(Bit8u)(val >> 24)); 02048 } 02049 addr += 16384; 02050 if( plane & 0x04 ) 02051 { 02052 writeHandler<false>(addr+0,(Bit8u)(val >> 0)); 02053 writeHandler<false>(addr+1,(Bit8u)(val >> 8)); 02054 writeHandler<false>(addr+2,(Bit8u)(val >> 16)); 02055 writeHandler<false>(addr+3,(Bit8u)(val >> 24)); 02056 } 02057 addr += 16384; 02058 if( plane & 0x08 ) 02059 { 02060 writeHandler<false>(addr+0,(Bit8u)(val >> 0)); 02061 writeHandler<false>(addr+1,(Bit8u)(val >> 8)); 02062 writeHandler<false>(addr+2,(Bit8u)(val >> 16)); 02063 writeHandler<false>(addr+3,(Bit8u)(val >> 24)); 02064 } 02065 02066 } 02067 Bit8u readb(PhysPt addr) { 02068 VGAMEM_USEC_read_delay(); 02069 addr = wrAddr( addr ) + ( vga.amstrad.read_plane * 16384u ); 02070 addr &= (64u*1024u-1u); 02071 return readHandler(addr); 02072 } 02073 Bit16u readw(PhysPt addr) { 02074 VGAMEM_USEC_read_delay(); 02075 addr = wrAddr( addr ) + ( vga.amstrad.read_plane * 16384u ); 02076 addr &= (64u*1024u-1u); 02077 return 02078 (readHandler(addr+0) << 0u) | 02079 (readHandler(addr+1) << 8u); 02080 } 02081 Bit32u readd(PhysPt addr) { 02082 VGAMEM_USEC_read_delay(); 02083 addr = wrAddr( addr ) + ( vga.amstrad.read_plane * 16384u ); 02084 addr &= (64u*1024u-1u); 02085 return 02086 (Bit32u)(readHandler(addr+0) << 0u) | 02087 (Bit32u)(readHandler(addr+1) << 8u) | 02088 (Bit32u)(readHandler(addr+2) << 16u) | 02089 (Bit32u)(readHandler(addr+3) << 24u); 02090 } 02091 02092 /* 02093 HostPt GetHostReadPt(Bitu phys_page) 02094 { 02095 if( vga.mode!=M_AMSTRAD ) 02096 { 02097 phys_page-=0xb8; 02098 //test for a unaliged bank, then replicate 2x16kb 02099 if (vga.tandy.mem_bank & 1) 02100 phys_page&=0x03; 02101 return vga.tandy.mem_base + (phys_page * 4096); 02102 } 02103 phys_page-=0xb8; 02104 return vga.tandy.mem_base + (phys_page*4096) + (vga.amstrad.read_plane * 16384) ; 02105 } 02106 */ 02107 /* 02108 HostPt GetHostWritePt(Bitu phys_page) { 02109 return GetHostReadPt( phys_page ); 02110 } 02111 */ 02112 }; 02113 02114 class VGA_HERC_Handler : public PageHandler { 02115 public: 02116 VGA_HERC_Handler() { 02117 flags=PFLAG_READABLE|PFLAG_WRITEABLE; 02118 } 02119 HostPt GetHostReadPt(Bitu phys_page) { 02120 (void)phys_page;//UNUSED 02121 // The 4kB map area is repeated in the 32kB range 02122 return &vga.mem.linear[0]; 02123 } 02124 HostPt GetHostWritePt(Bitu phys_page) { 02125 return GetHostReadPt( phys_page ); 02126 } 02127 }; 02128 02129 class VGA_Empty_Handler : public PageHandler { 02130 public: 02131 VGA_Empty_Handler() : PageHandler(PFLAG_NOCODE) {} 02132 Bit8u readb(PhysPt /*addr*/) { 02133 // LOG(LOG_VGA, LOG_NORMAL ) ( "Read from empty memory space at %x", addr ); 02134 return 0xff; 02135 } 02136 void writeb(PhysPt /*addr*/,Bit8u /*val*/) { 02137 // LOG(LOG_VGA, LOG_NORMAL ) ( "Write %x to empty memory space at %x", val, addr ); 02138 } 02139 }; 02140 02141 static struct vg { 02142 VGA_PC98_LFB_Handler map_lfb_pc98; 02143 VGA_Map_Handler map; 02144 VGA_Slow_CGA_Handler slow; 02145 // VGA_TEXT_PageHandler text; 02146 VGA_CGATEXT_PageHandler cgatext; 02147 VGA_MCGATEXT_PageHandler mcgatext; 02148 VGA_TANDY_PageHandler tandy; 02149 // VGA_ChainedEGA_Handler cega; 02150 // VGA_ChainedVGA_Handler cvga; 02151 VGA_ChainedVGA_Slow_Handler cvga_slow; 02152 // VGA_ET4000_ChainedVGA_Handler cvga_et4000; 02153 VGA_ET4000_ChainedVGA_Slow_Handler cvga_et4000_slow; 02154 // VGA_UnchainedEGA_Handler uega; 02155 VGA_UnchainedVGA_Handler uvga; 02156 VGA_PCJR_Handler pcjr; 02157 VGA_HERC_Handler herc; 02158 // VGA_LIN4_Handler lin4; 02159 VGA_LFB_Handler lfb; 02160 VGA_MMIO_Handler mmio; 02161 VGA_AMS_Handler ams; 02162 VGA_PC98_PageHandler pc98; 02163 VGA_PC98_TEXT_PageHandler pc98_text; 02164 VGA_PC98_CG_PageHandler pc98_cg; 02165 VGA_PC98_256MMIO_PageHandler pc98_256mmio; 02166 VGA_PC98_256BANK_PageHandler<0> pc98_256bank0; 02167 VGA_PC98_256BANK_PageHandler<1> pc98_256bank1; 02168 VGA_PC98_256Planar_PageHandler pc98_256planar; 02169 VGA_Empty_Handler empty; 02170 } vgaph; 02171 02172 void VGA_ChangedBank(void) { 02173 VGA_SetupHandlers(); 02174 } 02175 02176 void MEM_ResetPageHandler_Unmapped(Bitu phys_page, Bitu pages); 02177 void MEM_ResetPageHandler_RAM(Bitu phys_page, Bitu pages); 02178 02179 void VGA_SetupHandlers(void) { 02180 vga.svga.bank_read_full = vga.svga.bank_read*vga.svga.bank_size; 02181 vga.svga.bank_write_full = vga.svga.bank_write*vga.svga.bank_size; 02182 02183 PageHandler *newHandler; 02184 switch (machine) { 02185 case MCH_CGA: 02186 if (enableCGASnow && (vga.mode == M_TEXT || vga.mode == M_TANDY_TEXT)) 02187 MEM_SetPageHandler( VGA_PAGE_B8, 8, &vgaph.cgatext ); 02188 else 02189 MEM_SetPageHandler( VGA_PAGE_B8, 8, &vgaph.slow ); 02190 goto range_done; 02191 case MCH_MCGA://Based on real hardware, A0000-BFFFF is the 64KB of RAM mapped twice 02192 MEM_SetPageHandler( VGA_PAGE_A0, 16, &vgaph.mcgatext ); // A0000-AFFFF is the 64KB of video RAM 02193 MEM_ResetPageHandler_Unmapped( VGA_PAGE_B0, 8 ); // B0000-B7FFF is unmapped 02194 MEM_SetPageHandler( VGA_PAGE_B8, 8, &vgaph.mcgatext ); // B8000-BFFFF is the last 32KB half of video RAM, alias 02195 goto range_done; 02196 case MCH_PCJR: 02197 MEM_SetPageHandler( VGA_PAGE_A0, 16, &vgaph.empty ); 02198 MEM_SetPageHandler( VGA_PAGE_B0, 8, &vgaph.empty ); 02199 MEM_SetPageHandler( VGA_PAGE_B8, 8, &vgaph.pcjr ); 02200 goto range_done; 02201 case MCH_MDA: 02202 case MCH_HERC: 02203 MEM_SetPageHandler( VGA_PAGE_A0, 16, &vgaph.empty ); 02204 vgapages.base=VGA_PAGE_B0; 02205 /* NTS: Implemented according to [http://www.seasip.info/VintagePC/hercplus.html#regs] */ 02206 if (vga.herc.enable_bits & 0x2) { /* bit 1: page in upper 32KB */ 02207 vgapages.mask=0xffff; 02208 /* NTS: I don't know what Hercules graphics cards do if you set bit 1 but not bit 0. 02209 * For the time being, I'm assuming that they respond to 0xB8000+ because of bit 1 02210 * but only map to the first 4KB because of bit 0. Basically, a configuration no 02211 * software would actually use. */ 02212 if (vga.herc.enable_bits & 0x1) /* allow graphics and enable 0xB1000-0xB7FFF */ 02213 MEM_SetPageHandler(VGA_PAGE_B0,16,&vgaph.map); 02214 else 02215 MEM_SetPageHandler(VGA_PAGE_B0,16,&vgaph.herc); 02216 } else { 02217 vgapages.mask=0x7fff; 02218 // With hercules in 32kB mode it leaves a memory hole on 0xb800 02219 // and has MDA-compatible address wrapping when graphics are disabled 02220 if (vga.herc.enable_bits & 0x1) 02221 MEM_SetPageHandler(VGA_PAGE_B0,8,&vgaph.map); 02222 else 02223 MEM_SetPageHandler(VGA_PAGE_B0,8,&vgaph.herc); 02224 MEM_SetPageHandler(VGA_PAGE_B8,8,&vgaph.empty); 02225 } 02226 goto range_done; 02227 case MCH_TANDY: 02228 /* Always map 0xa000 - 0xbfff, might overwrite 0xb800 */ 02229 vgapages.base=VGA_PAGE_A0; 02230 vgapages.mask=0x1ffff; 02231 MEM_SetPageHandler(VGA_PAGE_A0, 32, &vgaph.map ); 02232 if ( vga.tandy.extended_ram & 1 ) { 02233 //You seem to be able to also map different 64kb banks, but have to figure that out 02234 //This seems to work so far though 02235 vga.tandy.draw_base = vga.mem.linear; 02236 vga.tandy.mem_base = vga.mem.linear; 02237 } else { 02238 vga.tandy.draw_base = TANDY_VIDBASE( vga.tandy.draw_bank * 16 * 1024); 02239 vga.tandy.mem_base = TANDY_VIDBASE( vga.tandy.mem_bank * 16 * 1024); 02240 MEM_SetPageHandler( VGA_PAGE_B8, 8, &vgaph.tandy ); 02241 } 02242 goto range_done; 02243 // MEM_SetPageHandler(vga.tandy.mem_bank<<2,vga.tandy.is_32k_mode ? 0x08 : 0x04,range_handler); 02244 case MCH_AMSTRAD: // Memory handler. 02245 MEM_SetPageHandler( 0xb8, 8, &vgaph.ams ); 02246 goto range_done; 02247 case EGAVGA_ARCH_CASE: 02248 break; 02249 case PC98_ARCH_CASE: 02250 MEM_SetPageHandler( VGA_PAGE_A0 + 0x00, 0x02, &vgaph.pc98_text );/* A0000-A1FFFh text layer, character data */ 02251 MEM_SetPageHandler( VGA_PAGE_A0 + 0x02, 0x02, &vgaph.pc98_text );/* A2000-A3FFFh text layer, attribute data + non-volatile RAM */ 02252 MEM_SetPageHandler( VGA_PAGE_A0 + 0x04, 0x01, &vgaph.pc98_cg ); /* A4000-A4FFFh character generator memory-mapped I/O */ 02253 MEM_ResetPageHandler_Unmapped( VGA_PAGE_A0 + 0x05, 0x03); /* A5000-A7FFFh not mapped */ 02254 02255 if (pc98_gdc_vramop & (1 << VOPBIT_VGA)) { 02256 if (pc98_gdc_vramop & (1 << VOPBIT_PEGC_PLANAR)) { 02257 MEM_SetPageHandler( VGA_PAGE_A0 + 0x08, 0x10, &vgaph.pc98_256planar );/* A8000-B7FFFh planar graphics (???) */ 02258 MEM_ResetPageHandler_Unmapped( VGA_PAGE_A0 + 0x18, 0x08); /* B8000-BFFFFh graphics layer, not mapped */ 02259 } 02260 else { 02261 MEM_SetPageHandler( VGA_PAGE_A0 + 0x08, 0x08, &vgaph.pc98_256bank0 );/* A8000-AFFFFh graphics layer, bank 0 */ 02262 MEM_SetPageHandler( VGA_PAGE_A0 + 0x10, 0x08, &vgaph.pc98_256bank1 );/* B0000-B7FFFh graphics layer, bank 1 */ 02263 MEM_ResetPageHandler_Unmapped( VGA_PAGE_A0 + 0x18, 0x08); /* B8000-BFFFFh graphics layer, not mapped */ 02264 } 02265 } 02266 else { 02267 MEM_SetPageHandler( VGA_PAGE_A0 + 0x08, 0x08, &vgaph.pc98 );/* A8000-AFFFFh graphics layer, B bitplane */ 02268 MEM_SetPageHandler( VGA_PAGE_A0 + 0x10, 0x08, &vgaph.pc98 );/* B0000-B7FFFh graphics layer, R bitplane */ 02269 MEM_SetPageHandler( VGA_PAGE_A0 + 0x18, 0x08, &vgaph.pc98 );/* B8000-BFFFFh graphics layer, G bitplane */ 02270 } 02271 02272 /* E0000-E7FFFh graphics layer 02273 * - In 8-color mode, E0000-E7FFFh is not mapped 02274 * - In 16-color mode, E0000-E7FFFh is the 4th bitplane (E) 02275 * - In 256-color mode, E0000-E7FFFh is memory-mapped I/O that controls the 256-color mode */ 02276 if (pc98_gdc_vramop & (1 << VOPBIT_VGA)) 02277 MEM_SetPageHandler(0xE0, 8, &vgaph.pc98_256mmio ); 02278 else if (pc98_gdc_vramop & (1 << VOPBIT_ANALOG)) 02279 MEM_SetPageHandler(0xE0, 8, &vgaph.pc98 ); 02280 else 02281 MEM_ResetPageHandler_Unmapped(0xE0, 8); 02282 02283 // TODO: What about PC-9821 systems with more than 15MB of RAM? Do they maintain a "hole" 02284 // in memory for this linear framebuffer? Intel motherboard chipsets of that era do 02285 // support a 15MB memory hole. 02286 if (MEM_TotalPages() <= 0xF00/*FIXME*/) { 02287 /* F00000-FF7FFFh linear framebuffer (256-packed) 02288 * - Does not exist except in 256-color mode. 02289 * - Switching from 256-color mode immediately unmaps this linear framebuffer. 02290 * - Switching to 256-color mode will immediately map the linear framebuffer if the enable bit is set in the PEGC MMIO registers */ 02291 if ((pc98_gdc_vramop & (1 << VOPBIT_VGA)) && pc98_pegc_linear_framebuffer_enabled()) 02292 MEM_SetPageHandler(0xF00, 512/*kb*/ / 4/*kb*/, &vgaph.map_lfb_pc98 ); 02293 else 02294 MEM_ResetPageHandler_Unmapped(0xF00, 512/*kb*/ / 4/*kb*/); 02295 } 02296 02297 goto range_done; 02298 default: 02299 LOG_MSG("Illegal machine type %d", machine ); 02300 return; 02301 } 02302 02303 /* This should be vga only */ 02304 switch (vga.mode) { 02305 case M_ERROR: 02306 default: 02307 return; 02308 case M_LIN15: 02309 case M_LIN16: 02310 case M_LIN24: 02311 case M_LIN32: 02312 case M_PACKED4: 02313 newHandler = &vgaph.map; 02314 break; 02315 case M_TEXT: 02316 case M_CGA2: 02317 case M_CGA4: 02318 /* EGA/VGA emulate CGA modes as chained */ 02319 /* fall through */ 02320 case M_LIN8: 02321 case M_LIN4: 02322 case M_VGA: 02323 case M_EGA: 02324 if (vga.config.chained) { 02325 if (vga.config.compatible_chain4) { 02326 /* NTS: ET4000AX cards appear to have a different chain4 implementation from everyone else: 02327 * the planar memory byte address is address >> 2 and bits A0-A1 select the plane, 02328 * where all other clones I've tested seem to write planar memory byte (address & ~3) 02329 * (one byte per 4 bytes) and bits A0-A1 select the plane. */ 02330 /* FIXME: Different chain4 implementation on ET4000 noted---is it true also for ET3000? */ 02331 if (svgaCard == SVGA_TsengET3K || svgaCard == SVGA_TsengET4K) 02332 newHandler = &vgaph.cvga_et4000_slow; 02333 else 02334 newHandler = &vgaph.cvga_slow; 02335 } 02336 else { 02337 /* this is needed for SVGA modes (Paradise, Tseng, S3) because SVGA 02338 * modes do NOT use the chain4 configuration */ 02339 newHandler = &vgaph.map; 02340 } 02341 } else { 02342 newHandler = &vgaph.uvga; 02343 } 02344 break; 02345 case M_AMSTRAD: 02346 newHandler = &vgaph.map; 02347 break; 02348 } 02349 switch ((vga.gfx.miscellaneous >> 2) & 3) { 02350 case 0: 02351 vgapages.base = VGA_PAGE_A0; 02352 switch (svgaCard) { 02353 case SVGA_TsengET3K: 02354 case SVGA_TsengET4K: 02355 vgapages.mask = 0x1ffff & vga.mem.memmask; 02356 break; 02357 /* NTS: Looking at the official ET4000 programming guide, it does in fact support the full 128KB */ 02358 case SVGA_S3Trio: 02359 default: 02360 vgapages.mask = 0xffff & vga.mem.memmask; 02361 break; 02362 } 02363 MEM_SetPageHandler(VGA_PAGE_A0, 32, newHandler ); 02364 break; 02365 case 1: 02366 vgapages.base = VGA_PAGE_A0; 02367 vgapages.mask = 0xffff & vga.mem.memmask; 02368 MEM_SetPageHandler( VGA_PAGE_A0, 16, newHandler ); 02369 MEM_SetPageHandler( VGA_PAGE_B0, 16, &vgaph.empty ); 02370 break; 02371 case 2: 02372 vgapages.base = VGA_PAGE_B0; 02373 vgapages.mask = 0x7fff & vga.mem.memmask; 02374 MEM_SetPageHandler( VGA_PAGE_B0, 8, newHandler ); 02375 MEM_SetPageHandler( VGA_PAGE_A0, 16, &vgaph.empty ); 02376 MEM_SetPageHandler( VGA_PAGE_B8, 8, &vgaph.empty ); 02377 break; 02378 case 3: 02379 vgapages.base = VGA_PAGE_B8; 02380 vgapages.mask = 0x7fff & vga.mem.memmask; 02381 MEM_SetPageHandler( VGA_PAGE_B8, 8, newHandler ); 02382 MEM_SetPageHandler( VGA_PAGE_A0, 16, &vgaph.empty ); 02383 MEM_SetPageHandler( VGA_PAGE_B0, 8, &vgaph.empty ); 02384 break; 02385 } 02386 if(svgaCard == SVGA_S3Trio && (vga.s3.ext_mem_ctrl & 0x10)) 02387 MEM_SetPageHandler(VGA_PAGE_A0, 16, &vgaph.mmio); 02388 02389 non_cga_ignore_oddeven_engage = (non_cga_ignore_oddeven && !(vga.mode == M_TEXT || vga.mode == M_CGA2 || vga.mode == M_CGA4)); 02390 02391 range_done: 02392 PAGING_ClearTLB(); 02393 } 02394 02395 void VGA_StartUpdateLFB(void) { 02396 /* please obey the Linear Address Window Size register! 02397 * Windows 3.1 S3 driver will reprogram the linear framebuffer down to 0xA0000 when entering a DOSBox 02398 * and assuming the full VRAM size will cause a LOT of problems! */ 02399 Bitu winsz = 0x10000; 02400 02401 switch (vga.s3.reg_58&3) { 02402 case 1: 02403 winsz = 1 << 20; //1MB 02404 break; 02405 case 2: 02406 winsz = 2 << 20; //2MB 02407 break; 02408 case 3: 02409 winsz = 4 << 20; //4MB 02410 break; 02411 // FIXME: What about the 8MB window? 02412 } 02413 02414 /* The LFB register has an enable bit */ 02415 if (!(vga.s3.reg_58 & 0x10)) { 02416 vga.lfb.page = (unsigned int)vga.s3.la_window << 4u; 02417 vga.lfb.addr = (unsigned int)vga.s3.la_window << 16u; 02418 vga.lfb.handler = NULL; 02419 MEM_SetLFB(0,0,NULL,NULL); 02420 } 02421 /* if the DOS application or Windows 3.1 driver attempts to put the linear framebuffer 02422 * below the top of memory, then we're probably entering a DOS VM and it's probably 02423 * a 64KB window. If it's not a 64KB window then print a warning. */ 02424 else if ((unsigned long)(vga.s3.la_window << 4UL) < (unsigned long)MEM_TotalPages()) { 02425 if (winsz != 0x10000) // 64KB window normal for entering a DOS VM in Windows 3.1 or legacy bank switching in DOS 02426 LOG(LOG_MISC,LOG_WARN)("S3 warning: Window size != 64KB and address conflict with system RAM!"); 02427 02428 vga.lfb.page = (unsigned int)vga.s3.la_window << 4u; 02429 vga.lfb.addr = (unsigned int)vga.s3.la_window << 16u; 02430 vga.lfb.handler = NULL; 02431 MEM_SetLFB(0,0,NULL,NULL); 02432 } 02433 else { 02434 vga.lfb.page = (unsigned int)vga.s3.la_window << 4u; 02435 vga.lfb.addr = (unsigned int)vga.s3.la_window << 16u; 02436 vga.lfb.handler = &vgaph.lfb; 02437 MEM_SetLFB((unsigned int)vga.s3.la_window << 4u,(unsigned int)vga.mem.memsize/4096u, vga.lfb.handler, &vgaph.mmio); 02438 } 02439 } 02440 02441 static bool VGA_Memory_ShutDown_init = false; 02442 02443 static void VGA_Memory_ShutDown(Section * /*sec*/) { 02444 MEM_SetPageHandler(VGA_PAGE_A0,32,&vgaph.empty); 02445 PAGING_ClearTLB(); 02446 02447 if (vga.mem.linear_orgptr != NULL) { 02448 delete[] vga.mem.linear_orgptr; 02449 vga.mem.linear_orgptr = NULL; 02450 vga.mem.linear = NULL; 02451 } 02452 } 02453 02454 void VGA_SetupMemory() { 02455 vga.svga.bank_read = vga.svga.bank_write = 0; 02456 vga.svga.bank_read_full = vga.svga.bank_write_full = 0; 02457 02458 if (vga.mem.linear == NULL) { 02459 VGA_Memory_ShutDown(NULL); 02460 02461 vga.mem.linear_orgptr = new Bit8u[vga.mem.memsize+32u]; 02462 memset(vga.mem.linear_orgptr,0,vga.mem.memsize+32u); 02463 vga.mem.linear=(Bit8u*)(((uintptr_t)vga.mem.linear_orgptr + 16ull-1ull) & ~(16ull-1ull)); 02464 02465 /* HACK. try to avoid stale pointers */ 02466 vga.draw.linear_base = vga.mem.linear; 02467 vga.tandy.draw_base = vga.mem.linear; 02468 vga.tandy.mem_base = vga.mem.linear; 02469 02470 /* PC-98 pointers */ 02471 pc98_pgraph_current_cpu_page = vga.mem.linear + PC98_VRAM_GRAPHICS_OFFSET; 02472 pc98_pgraph_current_display_page = vga.mem.linear + PC98_VRAM_GRAPHICS_OFFSET; 02473 02474 /* parallel system */ 02475 if (vga_alt_new_mode) { 02476 for (size_t si=0;si < VGA_Draw_2_elem;si++) 02477 vga.draw_2[si].draw_base = vga.mem.linear; 02478 02479 vga.draw_2[0].horz.char_pixel_mask = 0xFFu; 02480 vga.draw_2[0].vert.char_pixel_mask = 0x1Fu; 02481 } 02482 02483 /* may be related */ 02484 VGA_SetupHandlers(); 02485 } 02486 02487 vga.svga.bank_read = vga.svga.bank_write = 0; 02488 vga.svga.bank_read_full = vga.svga.bank_write_full = 0; 02489 vga.svga.bank_size = 0x10000; /* most common bank size is 64K */ 02490 02491 if (!VGA_Memory_ShutDown_init) { 02492 AddExitFunction(AddExitFunctionFuncPair(VGA_Memory_ShutDown)); 02493 VGA_Memory_ShutDown_init = true; 02494 } 02495 02496 if (machine==MCH_PCJR) { 02497 /* PCJr does not have dedicated graphics memory but uses 02498 conventional memory below 128k */ 02499 //TODO map? 02500 } 02501 } 02502 02503 // save state support 02504 void *VGA_PageHandler_Func[16] = 02505 { 02506 (void *) &vgaph.map, 02507 //(void *) &vgaph.changes, 02508 //(void *) &vgaph.text, 02509 (void *) &vgaph.tandy, 02510 //(void *) &vgaph.cega, 02511 //(void *) &vgaph.cvga, 02512 //(void *) &vgaph.uega, 02513 (void *) &vgaph.uvga, 02514 (void *) &vgaph.pcjr, 02515 (void *) &vgaph.herc, 02516 //(void *) &vgaph.lin4, 02517 (void *) &vgaph.lfb, 02518 //(void *) &vgaph.lfbchanges, 02519 (void *) &vgaph.mmio, 02520 (void *) &vgaph.empty, 02521 }; 02522 02523 void POD_Save_VGA_Memory( std::ostream& stream ) 02524 { 02525 // - static ptrs 02526 //Bit8u* linear; 02527 //Bit8u* linear_orgptr; 02528 02529 02530 // - pure data 02531 WRITE_POD_SIZE( vga.mem.linear, sizeof(Bit8u) * vga.mem.memsize); 02532 02533 //*************************************************** 02534 //*************************************************** 02535 02536 // static globals 02537 02538 // - pure struct data 02539 WRITE_POD( &vgapages, vgapages ); 02540 02541 // - static classes 02542 //WRITE_POD( &vgaph, vgaph ); 02543 } 02544 02545 02546 void POD_Load_VGA_Memory( std::istream& stream ) 02547 { 02548 // - static ptrs 02549 //Bit8u* linear; 02550 //Bit8u* linear_orgptr; 02551 02552 02553 // - pure data 02554 READ_POD_SIZE( vga.mem.linear, sizeof(Bit8u) * vga.mem.memsize); 02555 02556 //*************************************************** 02557 //*************************************************** 02558 02559 // static globals 02560 02561 // - pure struct data 02562 READ_POD( &vgapages, vgapages ); 02563 02564 // - static classes 02565 //READ_POD( &vgaph, vgaph ); 02566 }