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