1 /*
2 * Copyright (C) 2002-2010 The DOSBox Team
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 /* $Id: vga_memory.cpp,v 1.53 2009-07-04 21:23:35 qbix79 Exp $ */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include "dosbox.h"
24 #include "mem.h"
25 #include "vga.h"
26 #include "paging.h"
27 #include "pic.h"
28 #include "inout.h"
29 #include "setup.h"
30
31
32 #ifndef C_VGARAM_CHECKED
33 #define C_VGARAM_CHECKED 1
34 #endif
35
36 #if C_VGARAM_CHECKED
37 // Checked linear offset
38 #define CHECKED(v) ((v)&(vga.vmemwrap-1))
39 // Checked planar offset (latched access)
40 #define CHECKED2(v) ((v)&((vga.vmemwrap>>2)-1))
41 #else
42 #define CHECKED(v) (v)
43 #define CHECKED2(v) (v)
44 #endif
45
46 #define CHECKED3(v) ((v)&(vga.vmemwrap-1))
47 #define CHECKED4(v) ((v)&((vga.vmemwrap>>2)-1))
48
49
50 #ifdef VGA_KEEP_CHANGES
51 #define MEM_CHANGED( _MEM ) vga.changes.map[ (_MEM) >> VGA_CHANGE_SHIFT ] |= vga.changes.writeMask;
52 //#define MEM_CHANGED( _MEM ) vga.changes.map[ (_MEM) >> VGA_CHANGE_SHIFT ] = 1;
53 #else
54 #define MEM_CHANGED( _MEM )
55 #endif
56
57 #define TANDY_VIDBASE(_X_) &MemBase[ 0x80000 + (_X_)]
58
59 template <class Size>
hostWrite(HostPt off,Bitu val)60 static INLINE void hostWrite(HostPt off, Bitu val) {
61 if ( sizeof( Size ) == 1)
62 host_writeb( off, (Bit8u)val );
63 else if ( sizeof( Size ) == 2)
64 host_writew( off, (Bit16u)val );
65 else if ( sizeof( Size ) == 4)
66 host_writed( off, (Bit32u)val );
67 }
68
69 template <class Size>
hostRead(HostPt off)70 static INLINE Bitu hostRead(HostPt off ) {
71 if ( sizeof( Size ) == 1)
72 return host_readb( off );
73 else if ( sizeof( Size ) == 2)
74 return host_readw( off );
75 else if ( sizeof( Size ) == 4)
76 return host_readd( off );
77 return 0;
78 }
79
80
81 void VGA_MapMMIO(void);
82 //Nice one from DosEmu
RasterOp(Bit32u input,Bit32u mask)83 INLINE static Bit32u RasterOp(Bit32u input,Bit32u mask) {
84 switch (vga.config.raster_op) {
85 case 0x00: /* None */
86 return (input & mask) | (vga.latch.d & ~mask);
87 case 0x01: /* AND */
88 return (input | ~mask) & vga.latch.d;
89 case 0x02: /* OR */
90 return (input & mask) | vga.latch.d;
91 case 0x03: /* XOR */
92 return (input & mask) ^ vga.latch.d;
93 };
94 return 0;
95 }
96
ModeOperation(Bit8u val)97 INLINE static Bit32u ModeOperation(Bit8u val) {
98 Bit32u full;
99 switch (vga.config.write_mode) {
100 case 0x00:
101 // 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.
102 val=((val >> vga.config.data_rotate) | (val << (8-vga.config.data_rotate)));
103 full=ExpandTable[val];
104 full=(full & vga.config.full_not_enable_set_reset) | vga.config.full_enable_and_set_reset;
105 full=RasterOp(full,vga.config.full_bit_mask);
106 break;
107 case 0x01:
108 // 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.
109 full=vga.latch.d;
110 break;
111 case 0x02:
112 //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.
113 full=RasterOp(FillTable[val&0xF],vga.config.full_bit_mask);
114 break;
115 case 0x03:
116 // 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.
117 val=((val >> vga.config.data_rotate) | (val << (8-vga.config.data_rotate)));
118 full=RasterOp(vga.config.full_set_reset,ExpandTable[val] & vga.config.full_bit_mask);
119 break;
120 default:
121 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:Unsupported write mode %d",vga.config.write_mode);
122 full=0;
123 break;
124 }
125 return full;
126 }
127
128 /* Gonna assume that whoever maps vga memory, maps it on 32/64kb boundary */
129
130 #define VGA_PAGES (128/4)
131 #define VGA_PAGE_A0 (0xA0000/4096)
132 #define VGA_PAGE_B0 (0xB0000/4096)
133 #define VGA_PAGE_B8 (0xB8000/4096)
134
135 static struct {
136 Bitu base, mask;
137 } vgapages;
138
139 class VGA_UnchainedRead_Handler : public PageHandler {
140 public:
readHandler(PhysPt start)141 Bitu readHandler(PhysPt start) {
142 vga.latch.d=((Bit32u*)vga.mem.linear)[start];
143 switch (vga.config.read_mode) {
144 case 0:
145 return (vga.latch.b[vga.config.read_map_select]);
146 case 1:
147 VGA_Latch templatch;
148 templatch.d=(vga.latch.d & FillTable[vga.config.color_dont_care]) ^ FillTable[vga.config.color_compare & vga.config.color_dont_care];
149 return (Bit8u)~(templatch.b[0] | templatch.b[1] | templatch.b[2] | templatch.b[3]);
150 }
151 return 0;
152 }
153 public:
readb(PhysPt addr)154 Bitu readb(PhysPt addr) {
155 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
156 addr += vga.svga.bank_read_full;
157 addr = CHECKED2(addr);
158 return readHandler(addr);
159 }
readw(PhysPt addr)160 Bitu readw(PhysPt addr) {
161 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
162 addr += vga.svga.bank_read_full;
163 addr = CHECKED2(addr);
164 Bitu ret = (readHandler(addr+0) << 0);
165 ret |= (readHandler(addr+1) << 8);
166 return ret;
167 }
readd(PhysPt addr)168 Bitu readd(PhysPt addr) {
169 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
170 addr += vga.svga.bank_read_full;
171 addr = CHECKED2(addr);
172 Bitu ret = (readHandler(addr+0) << 0);
173 ret |= (readHandler(addr+1) << 8);
174 ret |= (readHandler(addr+2) << 16);
175 ret |= (readHandler(addr+3) << 24);
176 return ret;
177 }
178 };
179
180 class VGA_ChainedEGA_Handler : public PageHandler {
181 public:
readHandler(PhysPt addr)182 Bitu readHandler(PhysPt addr) {
183 return vga.mem.linear[addr];
184 }
writeHandler(PhysPt start,Bit8u val)185 void writeHandler(PhysPt start, Bit8u val) {
186 ModeOperation(val);
187 /* Update video memory and the pixel buffer */
188 VGA_Latch pixels;
189 vga.mem.linear[start] = val;
190 start >>= 2;
191 pixels.d=((Bit32u*)vga.mem.linear)[start];
192
193 Bit8u * write_pixels=&vga.fastmem[start<<3];
194
195 Bit32u colors0_3, colors4_7;
196 VGA_Latch temp;temp.d=(pixels.d>>4) & 0x0f0f0f0f;
197 colors0_3 =
198 Expand16Table[0][temp.b[0]] |
199 Expand16Table[1][temp.b[1]] |
200 Expand16Table[2][temp.b[2]] |
201 Expand16Table[3][temp.b[3]];
202 *(Bit32u *)write_pixels=colors0_3;
203 temp.d=pixels.d & 0x0f0f0f0f;
204 colors4_7 =
205 Expand16Table[0][temp.b[0]] |
206 Expand16Table[1][temp.b[1]] |
207 Expand16Table[2][temp.b[2]] |
208 Expand16Table[3][temp.b[3]];
209 *(Bit32u *)(write_pixels+4)=colors4_7;
210 }
211 public:
VGA_ChainedEGA_Handler()212 VGA_ChainedEGA_Handler() {
213 flags=PFLAG_NOCODE;
214 }
writeb(PhysPt addr,Bitu val)215 void writeb(PhysPt addr,Bitu val) {
216 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
217 addr += vga.svga.bank_write_full;
218 addr = CHECKED(addr);
219 MEM_CHANGED( addr << 3);
220 writeHandler(addr+0,(Bit8u)(val >> 0));
221 }
writew(PhysPt addr,Bitu val)222 void writew(PhysPt addr,Bitu val) {
223 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
224 addr += vga.svga.bank_write_full;
225 addr = CHECKED(addr);
226 MEM_CHANGED( addr << 3);
227 writeHandler(addr+0,(Bit8u)(val >> 0));
228 writeHandler(addr+1,(Bit8u)(val >> 8));
229 }
writed(PhysPt addr,Bitu val)230 void writed(PhysPt addr,Bitu val) {
231 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
232 addr += vga.svga.bank_write_full;
233 addr = CHECKED(addr);
234 MEM_CHANGED( addr << 3);
235 writeHandler(addr+0,(Bit8u)(val >> 0));
236 writeHandler(addr+1,(Bit8u)(val >> 8));
237 writeHandler(addr+2,(Bit8u)(val >> 16));
238 writeHandler(addr+3,(Bit8u)(val >> 24));
239 }
readb(PhysPt addr)240 Bitu readb(PhysPt addr) {
241 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
242 addr += vga.svga.bank_read_full;
243 addr = CHECKED(addr);
244 return readHandler(addr);
245 }
readw(PhysPt addr)246 Bitu readw(PhysPt addr) {
247 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
248 addr += vga.svga.bank_read_full;
249 addr = CHECKED(addr);
250 Bitu ret = (readHandler(addr+0) << 0);
251 ret |= (readHandler(addr+1) << 8);
252 return ret;
253 }
readd(PhysPt addr)254 Bitu readd(PhysPt addr) {
255 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
256 addr += vga.svga.bank_read_full;
257 addr = CHECKED(addr);
258 Bitu ret = (readHandler(addr+0) << 0);
259 ret |= (readHandler(addr+1) << 8);
260 ret |= (readHandler(addr+2) << 16);
261 ret |= (readHandler(addr+3) << 24);
262 return ret;
263 }
264 };
265
266 class VGA_UnchainedEGA_Handler : public VGA_UnchainedRead_Handler {
267 public:
268 template< bool wrapping>
writeHandler(PhysPt start,Bit8u val)269 void writeHandler(PhysPt start, Bit8u val) {
270 Bit32u data=ModeOperation(val);
271 /* Update video memory and the pixel buffer */
272 VGA_Latch pixels;
273 pixels.d=((Bit32u*)vga.mem.linear)[start];
274 pixels.d&=vga.config.full_not_map_mask;
275 pixels.d|=(data & vga.config.full_map_mask);
276 ((Bit32u*)vga.mem.linear)[start]=pixels.d;
277 Bit8u * write_pixels=&vga.fastmem[start<<3];
278
279 Bit32u colors0_3, colors4_7;
280 VGA_Latch temp;temp.d=(pixels.d>>4) & 0x0f0f0f0f;
281 colors0_3 =
282 Expand16Table[0][temp.b[0]] |
283 Expand16Table[1][temp.b[1]] |
284 Expand16Table[2][temp.b[2]] |
285 Expand16Table[3][temp.b[3]];
286 *(Bit32u *)write_pixels=colors0_3;
287 temp.d=pixels.d & 0x0f0f0f0f;
288 colors4_7 =
289 Expand16Table[0][temp.b[0]] |
290 Expand16Table[1][temp.b[1]] |
291 Expand16Table[2][temp.b[2]] |
292 Expand16Table[3][temp.b[3]];
293 *(Bit32u *)(write_pixels+4)=colors4_7;
294 }
295 public:
VGA_UnchainedEGA_Handler()296 VGA_UnchainedEGA_Handler() {
297 flags=PFLAG_NOCODE;
298 }
writeb(PhysPt addr,Bitu val)299 void writeb(PhysPt addr,Bitu val) {
300 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
301 addr += vga.svga.bank_write_full;
302 addr = CHECKED2(addr);
303 MEM_CHANGED( addr << 3);
304 writeHandler<true>(addr+0,(Bit8u)(val >> 0));
305 }
writew(PhysPt addr,Bitu val)306 void writew(PhysPt addr,Bitu val) {
307 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
308 addr += vga.svga.bank_write_full;
309 addr = CHECKED2(addr);
310 MEM_CHANGED( addr << 3);
311 writeHandler<true>(addr+0,(Bit8u)(val >> 0));
312 writeHandler<true>(addr+1,(Bit8u)(val >> 8));
313 }
writed(PhysPt addr,Bitu val)314 void writed(PhysPt addr,Bitu val) {
315 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
316 addr += vga.svga.bank_write_full;
317 addr = CHECKED2(addr);
318 MEM_CHANGED( addr << 3);
319 writeHandler<true>(addr+0,(Bit8u)(val >> 0));
320 writeHandler<true>(addr+1,(Bit8u)(val >> 8));
321 writeHandler<true>(addr+2,(Bit8u)(val >> 16));
322 writeHandler<true>(addr+3,(Bit8u)(val >> 24));
323 }
324 };
325
326 //Slighly unusual version, will directly write 8,16,32 bits values
327 class VGA_ChainedVGA_Handler : public PageHandler {
328 public:
VGA_ChainedVGA_Handler()329 VGA_ChainedVGA_Handler() {
330 flags=PFLAG_NOCODE;
331 }
332 template <class Size>
readHandler(PhysPt addr)333 static INLINE Bitu readHandler(PhysPt addr ) {
334 return hostRead<Size>( &vga.mem.linear[((addr&~3)<<2)+(addr&3)] );
335 }
336 template <class Size>
writeCache(PhysPt addr,Bitu val)337 static INLINE void writeCache(PhysPt addr, Bitu val) {
338 hostWrite<Size>( &vga.fastmem[addr], val );
339 if (GCC_UNLIKELY(addr < 320)) {
340 // And replicate the first line
341 hostWrite<Size>( &vga.fastmem[addr+64*1024], val );
342 }
343 }
344 template <class Size>
writeHandler(PhysPt addr,Bitu val)345 static INLINE void writeHandler(PhysPt addr, Bitu val) {
346 // No need to check for compatible chains here, this one is only enabled if that bit is set
347 hostWrite<Size>( &vga.mem.linear[((addr&~3)<<2)+(addr&3)], val );
348 }
readb(PhysPt addr)349 Bitu readb(PhysPt addr ) {
350 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
351 addr += vga.svga.bank_read_full;
352 addr = CHECKED(addr);
353 return readHandler<Bit8u>( addr );
354 }
readw(PhysPt addr)355 Bitu readw(PhysPt addr ) {
356 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
357 addr += vga.svga.bank_read_full;
358 addr = CHECKED(addr);
359 if (GCC_UNLIKELY(addr & 1)) {
360 Bitu ret = (readHandler<Bit8u>( addr+0 ) << 0 );
361 ret |= (readHandler<Bit8u>( addr+1 ) << 8 );
362 return ret;
363 } else
364 return readHandler<Bit16u>( addr );
365 }
readd(PhysPt addr)366 Bitu readd(PhysPt addr ) {
367 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
368 addr += vga.svga.bank_read_full;
369 addr = CHECKED(addr);
370 if (GCC_UNLIKELY(addr & 3)) {
371 Bitu ret = (readHandler<Bit8u>( addr+0 ) << 0 );
372 ret |= (readHandler<Bit8u>( addr+1 ) << 8 );
373 ret |= (readHandler<Bit8u>( addr+2 ) << 16 );
374 ret |= (readHandler<Bit8u>( addr+3 ) << 24 );
375 return ret;
376 } else
377 return readHandler<Bit32u>( addr );
378 }
writeb(PhysPt addr,Bitu val)379 void writeb(PhysPt addr, Bitu val ) {
380 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
381 addr += vga.svga.bank_write_full;
382 addr = CHECKED(addr);
383 MEM_CHANGED( addr );
384 writeHandler<Bit8u>( addr, val );
385 writeCache<Bit8u>( addr, val );
386 }
writew(PhysPt addr,Bitu val)387 void writew(PhysPt addr,Bitu val) {
388 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
389 addr += vga.svga.bank_write_full;
390 addr = CHECKED(addr);
391 MEM_CHANGED( addr );
392 // MEM_CHANGED( addr + 1);
393 if (GCC_UNLIKELY(addr & 1)) {
394 writeHandler<Bit8u>( addr+0, val >> 0 );
395 writeHandler<Bit8u>( addr+1, val >> 8 );
396 } else {
397 writeHandler<Bit16u>( addr, val );
398 }
399 writeCache<Bit16u>( addr, val );
400 }
writed(PhysPt addr,Bitu val)401 void writed(PhysPt addr,Bitu val) {
402 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
403 addr += vga.svga.bank_write_full;
404 addr = CHECKED(addr);
405 MEM_CHANGED( addr );
406 // MEM_CHANGED( addr + 3);
407 if (GCC_UNLIKELY(addr & 3)) {
408 writeHandler<Bit8u>( addr+0, val >> 0 );
409 writeHandler<Bit8u>( addr+1, val >> 8 );
410 writeHandler<Bit8u>( addr+2, val >> 16 );
411 writeHandler<Bit8u>( addr+3, val >> 24 );
412 } else {
413 writeHandler<Bit32u>( addr, val );
414 }
415 writeCache<Bit32u>( addr, val );
416 }
417 };
418
419 class VGA_UnchainedVGA_Handler : public VGA_UnchainedRead_Handler {
420 public:
writeHandler(PhysPt addr,Bit8u val)421 void writeHandler( PhysPt addr, Bit8u val ) {
422 Bit32u data=ModeOperation(val);
423 VGA_Latch pixels;
424 pixels.d=((Bit32u*)vga.mem.linear)[addr];
425 pixels.d&=vga.config.full_not_map_mask;
426 pixels.d|=(data & vga.config.full_map_mask);
427 ((Bit32u*)vga.mem.linear)[addr]=pixels.d;
428 // if(vga.config.compatible_chain4)
429 // ((Bit32u*)vga.mem.linear)[CHECKED2(addr+64*1024)]=pixels.d;
430 }
431 public:
VGA_UnchainedVGA_Handler()432 VGA_UnchainedVGA_Handler() {
433 flags=PFLAG_NOCODE;
434 }
writeb(PhysPt addr,Bitu val)435 void writeb(PhysPt addr,Bitu val) {
436 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
437 addr += vga.svga.bank_write_full;
438 addr = CHECKED2(addr);
439 MEM_CHANGED( addr << 2 );
440 writeHandler(addr+0,(Bit8u)(val >> 0));
441 }
writew(PhysPt addr,Bitu val)442 void writew(PhysPt addr,Bitu val) {
443 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
444 addr += vga.svga.bank_write_full;
445 addr = CHECKED2(addr);
446 MEM_CHANGED( addr << 2);
447 writeHandler(addr+0,(Bit8u)(val >> 0));
448 writeHandler(addr+1,(Bit8u)(val >> 8));
449 }
writed(PhysPt addr,Bitu val)450 void writed(PhysPt addr,Bitu val) {
451 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
452 addr += vga.svga.bank_write_full;
453 addr = CHECKED2(addr);
454 MEM_CHANGED( addr << 2);
455 writeHandler(addr+0,(Bit8u)(val >> 0));
456 writeHandler(addr+1,(Bit8u)(val >> 8));
457 writeHandler(addr+2,(Bit8u)(val >> 16));
458 writeHandler(addr+3,(Bit8u)(val >> 24));
459 }
460 };
461
462 class VGA_TEXT_PageHandler : public PageHandler {
463 public:
VGA_TEXT_PageHandler()464 VGA_TEXT_PageHandler() {
465 flags=PFLAG_NOCODE;
466 }
readb(PhysPt addr)467 Bitu readb(PhysPt addr) {
468 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
469 return vga.draw.font[addr];
470 }
writeb(PhysPt addr,Bitu val)471 void writeb(PhysPt addr,Bitu val){
472 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
473 if (vga.seq.map_mask & 0x4) {
474 vga.draw.font[addr]=(Bit8u)val;
475 }
476 }
477 };
478
479 class VGA_Map_Handler : public PageHandler {
480 public:
VGA_Map_Handler()481 VGA_Map_Handler() {
482 flags=PFLAG_READABLE|PFLAG_WRITEABLE|PFLAG_NOCODE;
483 }
GetHostReadPt(Bitu phys_page)484 HostPt GetHostReadPt(Bitu phys_page) {
485 phys_page-=vgapages.base;
486 return &vga.mem.linear[CHECKED3(vga.svga.bank_read_full+phys_page*4096)];
487 }
GetHostWritePt(Bitu phys_page)488 HostPt GetHostWritePt(Bitu phys_page) {
489 phys_page-=vgapages.base;
490 return &vga.mem.linear[CHECKED3(vga.svga.bank_write_full+phys_page*4096)];
491 }
492 };
493
494 class VGA_Changes_Handler : public PageHandler {
495 public:
VGA_Changes_Handler()496 VGA_Changes_Handler() {
497 flags=PFLAG_NOCODE;
498 }
readb(PhysPt addr)499 Bitu readb(PhysPt addr) {
500 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
501 addr += vga.svga.bank_read_full;
502 addr = CHECKED(addr);
503 return hostRead<Bit8u>( &vga.mem.linear[addr] );
504 }
readw(PhysPt addr)505 Bitu readw(PhysPt addr) {
506 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
507 addr += vga.svga.bank_read_full;
508 addr = CHECKED(addr);
509 return hostRead<Bit16u>( &vga.mem.linear[addr] );
510 }
readd(PhysPt addr)511 Bitu readd(PhysPt addr) {
512 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
513 addr += vga.svga.bank_read_full;
514 addr = CHECKED(addr);
515 return hostRead<Bit32u>( &vga.mem.linear[addr] );
516 }
writeb(PhysPt addr,Bitu val)517 void writeb(PhysPt addr,Bitu val) {
518 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
519 addr += vga.svga.bank_write_full;
520 addr = CHECKED(addr);
521 MEM_CHANGED( addr );
522 hostWrite<Bit8u>( &vga.mem.linear[addr], val );
523 }
writew(PhysPt addr,Bitu val)524 void writew(PhysPt addr,Bitu val) {
525 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
526 addr += vga.svga.bank_write_full;
527 addr = CHECKED(addr);
528 MEM_CHANGED( addr );
529 hostWrite<Bit16u>( &vga.mem.linear[addr], val );
530 }
writed(PhysPt addr,Bitu val)531 void writed(PhysPt addr,Bitu val) {
532 addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask;
533 addr += vga.svga.bank_write_full;
534 addr = CHECKED(addr);
535 MEM_CHANGED( addr );
536 hostWrite<Bit32u>( &vga.mem.linear[addr], val );
537 }
538 };
539
540 class VGA_LIN4_Handler : public VGA_UnchainedEGA_Handler {
541 public:
VGA_LIN4_Handler()542 VGA_LIN4_Handler() {
543 flags=PFLAG_NOCODE;
544 }
writeb(PhysPt addr,Bitu val)545 void writeb(PhysPt addr,Bitu val) {
546 addr = vga.svga.bank_write_full + (PAGING_GetPhysicalAddress(addr) & 0xffff);
547 addr = CHECKED4(addr);
548 MEM_CHANGED( addr << 3 );
549 writeHandler<false>(addr+0,(Bit8u)(val >> 0));
550 }
writew(PhysPt addr,Bitu val)551 void writew(PhysPt addr,Bitu val) {
552 addr = vga.svga.bank_write_full + (PAGING_GetPhysicalAddress(addr) & 0xffff);
553 addr = CHECKED4(addr);
554 MEM_CHANGED( addr << 3 );
555 writeHandler<false>(addr+0,(Bit8u)(val >> 0));
556 writeHandler<false>(addr+1,(Bit8u)(val >> 8));
557 }
writed(PhysPt addr,Bitu val)558 void writed(PhysPt addr,Bitu val) {
559 addr = vga.svga.bank_write_full + (PAGING_GetPhysicalAddress(addr) & 0xffff);
560 addr = CHECKED4(addr);
561 MEM_CHANGED( addr << 3 );
562 writeHandler<false>(addr+0,(Bit8u)(val >> 0));
563 writeHandler<false>(addr+1,(Bit8u)(val >> 8));
564 writeHandler<false>(addr+2,(Bit8u)(val >> 16));
565 writeHandler<false>(addr+3,(Bit8u)(val >> 24));
566 }
readb(PhysPt addr)567 Bitu readb(PhysPt addr) {
568 addr = vga.svga.bank_read_full + (PAGING_GetPhysicalAddress(addr) & 0xffff);
569 addr = CHECKED4(addr);
570 return readHandler(addr);
571 }
readw(PhysPt addr)572 Bitu readw(PhysPt addr) {
573 addr = vga.svga.bank_read_full + (PAGING_GetPhysicalAddress(addr) & 0xffff);
574 addr = CHECKED4(addr);
575 Bitu ret = (readHandler(addr+0) << 0);
576 ret |= (readHandler(addr+1) << 8);
577 return ret;
578 }
readd(PhysPt addr)579 Bitu readd(PhysPt addr) {
580 addr = vga.svga.bank_read_full + (PAGING_GetPhysicalAddress(addr) & 0xffff);
581 addr = CHECKED4(addr);
582 Bitu ret = (readHandler(addr+0) << 0);
583 ret |= (readHandler(addr+1) << 8);
584 ret |= (readHandler(addr+2) << 16);
585 ret |= (readHandler(addr+3) << 24);
586 return ret;
587 }
588 };
589
590
591 class VGA_LFBChanges_Handler : public PageHandler {
592 public:
VGA_LFBChanges_Handler()593 VGA_LFBChanges_Handler() {
594 flags=PFLAG_NOCODE;
595 }
readb(PhysPt addr)596 Bitu readb(PhysPt addr) {
597 addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr;
598 addr = CHECKED(addr);
599 return hostRead<Bit8u>( &vga.mem.linear[addr] );
600 }
readw(PhysPt addr)601 Bitu readw(PhysPt addr) {
602 addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr;
603 addr = CHECKED(addr);
604 return hostRead<Bit16u>( &vga.mem.linear[addr] );
605 }
readd(PhysPt addr)606 Bitu readd(PhysPt addr) {
607 addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr;
608 addr = CHECKED(addr);
609 return hostRead<Bit32u>( &vga.mem.linear[addr] );
610 }
writeb(PhysPt addr,Bitu val)611 void writeb(PhysPt addr,Bitu val) {
612 addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr;
613 addr = CHECKED(addr);
614 hostWrite<Bit8u>( &vga.mem.linear[addr], val );
615 MEM_CHANGED( addr );
616 }
writew(PhysPt addr,Bitu val)617 void writew(PhysPt addr,Bitu val) {
618 addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr;
619 addr = CHECKED(addr);
620 hostWrite<Bit16u>( &vga.mem.linear[addr], val );
621 MEM_CHANGED( addr );
622 }
writed(PhysPt addr,Bitu val)623 void writed(PhysPt addr,Bitu val) {
624 addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr;
625 addr = CHECKED(addr);
626 hostWrite<Bit32u>( &vga.mem.linear[addr], val );
627 MEM_CHANGED( addr );
628 }
629 };
630
631 class VGA_LFB_Handler : public PageHandler {
632 public:
VGA_LFB_Handler()633 VGA_LFB_Handler() {
634 flags=PFLAG_READABLE|PFLAG_WRITEABLE|PFLAG_NOCODE;
635 }
GetHostReadPt(Bitu phys_page)636 HostPt GetHostReadPt( Bitu phys_page ) {
637 phys_page -= vga.lfb.page;
638 return &vga.mem.linear[CHECKED3(phys_page * 4096)];
639 }
GetHostWritePt(Bitu phys_page)640 HostPt GetHostWritePt( Bitu phys_page ) {
641 return GetHostReadPt( phys_page );
642 }
643 };
644
645 extern void XGA_Write(Bitu port, Bitu val, Bitu len);
646 extern Bitu XGA_Read(Bitu port, Bitu len);
647
648 class VGA_MMIO_Handler : public PageHandler {
649 public:
VGA_MMIO_Handler()650 VGA_MMIO_Handler() {
651 flags=PFLAG_NOCODE;
652 }
writeb(PhysPt addr,Bitu val)653 void writeb(PhysPt addr,Bitu val) {
654 Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff;
655 XGA_Write(port, val, 1);
656 }
writew(PhysPt addr,Bitu val)657 void writew(PhysPt addr,Bitu val) {
658 Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff;
659 XGA_Write(port, val, 2);
660 }
writed(PhysPt addr,Bitu val)661 void writed(PhysPt addr,Bitu val) {
662 Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff;
663 XGA_Write(port, val, 4);
664 }
665
readb(PhysPt addr)666 Bitu readb(PhysPt addr) {
667 Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff;
668 return XGA_Read(port, 1);
669 }
readw(PhysPt addr)670 Bitu readw(PhysPt addr) {
671 Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff;
672 return XGA_Read(port, 2);
673 }
readd(PhysPt addr)674 Bitu readd(PhysPt addr) {
675 Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff;
676 return XGA_Read(port, 4);
677 }
678 };
679
680 class VGA_TANDY_PageHandler : public PageHandler {
681 public:
VGA_TANDY_PageHandler()682 VGA_TANDY_PageHandler() {
683 flags=PFLAG_READABLE|PFLAG_WRITEABLE;
684 // |PFLAG_NOCODE;
685 }
GetHostReadPt(Bitu phys_page)686 HostPt GetHostReadPt(Bitu phys_page) {
687 if (vga.tandy.mem_bank & 1)
688 phys_page&=0x03;
689 else
690 phys_page&=0x07;
691 return vga.tandy.mem_base + (phys_page * 4096);
692 }
GetHostWritePt(Bitu phys_page)693 HostPt GetHostWritePt(Bitu phys_page) {
694 return GetHostReadPt( phys_page );
695 }
696 };
697
698
699 class VGA_PCJR_Handler : public PageHandler {
700 public:
VGA_PCJR_Handler()701 VGA_PCJR_Handler() {
702 flags=PFLAG_READABLE|PFLAG_WRITEABLE;
703 }
GetHostReadPt(Bitu phys_page)704 HostPt GetHostReadPt(Bitu phys_page) {
705 phys_page-=0xb8;
706 //test for a unaliged bank, then replicate 2x16kb
707 if (vga.tandy.mem_bank & 1)
708 phys_page&=0x03;
709 return vga.tandy.mem_base + (phys_page * 4096);
710 }
GetHostWritePt(Bitu phys_page)711 HostPt GetHostWritePt(Bitu phys_page) {
712 return GetHostReadPt( phys_page );
713 }
714 };
715
716 class VGA_Empty_Handler : public PageHandler {
717 public:
VGA_Empty_Handler()718 VGA_Empty_Handler() {
719 flags=PFLAG_NOCODE;
720 }
readb(PhysPt)721 Bitu readb(PhysPt /*addr*/) {
722 // LOG(LOG_VGA, LOG_NORMAL ) ( "Read from empty memory space at %x", addr );
723 return 0xff;
724 }
writeb(PhysPt,Bitu)725 void writeb(PhysPt /*addr*/,Bitu /*val*/) {
726 // LOG(LOG_VGA, LOG_NORMAL ) ( "Write %x to empty memory space at %x", val, addr );
727 }
728 };
729
730 static struct vg {
731 VGA_Map_Handler map;
732 VGA_Changes_Handler changes;
733 VGA_TEXT_PageHandler text;
734 VGA_TANDY_PageHandler tandy;
735 VGA_ChainedEGA_Handler cega;
736 VGA_ChainedVGA_Handler cvga;
737 VGA_UnchainedEGA_Handler uega;
738 VGA_UnchainedVGA_Handler uvga;
739 VGA_PCJR_Handler pcjr;
740 VGA_LIN4_Handler lin4;
741 VGA_LFB_Handler lfb;
742 VGA_LFBChanges_Handler lfbchanges;
743 VGA_MMIO_Handler mmio;
744 VGA_Empty_Handler empty;
745 } vgaph;
746
VGA_ChangedBank(void)747 void VGA_ChangedBank(void) {
748 #ifndef VGA_LFB_MAPPED
749 //If the mode is accurate than the correct mapper must have been installed already
750 if ( vga.mode >= M_LIN4 && vga.mode <= M_LIN32 ) {
751 return;
752 }
753 #endif
754 VGA_SetupHandlers();
755 }
756
VGA_SetupHandlers(void)757 void VGA_SetupHandlers(void) {
758 vga.svga.bank_read_full = vga.svga.bank_read*vga.svga.bank_size;
759 vga.svga.bank_write_full = vga.svga.bank_write*vga.svga.bank_size;
760
761 PageHandler *newHandler;
762 switch (machine) {
763 case MCH_CGA:
764 case MCH_PCJR:
765 MEM_SetPageHandler( VGA_PAGE_B8, 8, &vgaph.pcjr );
766 goto range_done;
767 case MCH_HERC:
768 vgapages.base=VGA_PAGE_B0;
769 if (vga.herc.enable_bits & 0x2) {
770 vgapages.mask=0xffff;
771 MEM_SetPageHandler(VGA_PAGE_B0,16,&vgaph.map);
772 } else {
773 vgapages.mask=0x7fff;
774 /* With hercules in 32kb mode it leaves a memory hole on 0xb800 */
775 MEM_SetPageHandler(VGA_PAGE_B0,8,&vgaph.map);
776 MEM_SetPageHandler(VGA_PAGE_B8,8,&vgaph.empty);
777 }
778 goto range_done;
779 case MCH_TANDY:
780 /* Always map 0xa000 - 0xbfff, might overwrite 0xb800 */
781 vgapages.base=VGA_PAGE_A0;
782 vgapages.mask=0x1ffff;
783 MEM_SetPageHandler(VGA_PAGE_A0, 32, &vgaph.map );
784 if ( vga.tandy.extended_ram & 1 ) {
785 //You seem to be able to also map different 64kb banks, but have to figure that out
786 //This seems to work so far though
787 vga.tandy.draw_base = vga.mem.linear;
788 vga.tandy.mem_base = vga.mem.linear;
789 } else {
790 vga.tandy.draw_base = TANDY_VIDBASE( vga.tandy.draw_bank * 16 * 1024);
791 vga.tandy.mem_base = TANDY_VIDBASE( vga.tandy.mem_bank * 16 * 1024);
792 MEM_SetPageHandler( 0xb8, 8, &vgaph.tandy );
793 }
794 goto range_done;
795 // MEM_SetPageHandler(vga.tandy.mem_bank<<2,vga.tandy.is_32k_mode ? 0x08 : 0x04,range_handler);
796 case EGAVGA_ARCH_CASE:
797 break;
798 default:
799 LOG_MSG("Illegal machine type %d", machine );
800 return;
801 }
802
803 /* This should be vga only */
804 switch (vga.mode) {
805 case M_ERROR:
806 default:
807 return;
808 case M_LIN4:
809 newHandler = &vgaph.lin4;
810 break;
811 case M_LIN15:
812 case M_LIN16:
813 case M_LIN32:
814 #ifdef VGA_LFB_MAPPED
815 newHandler = &vgaph.map;
816 #else
817 newHandler = &vgaph.changes;
818 #endif
819 break;
820 case M_LIN8:
821 case M_VGA:
822 if (vga.config.chained) {
823 if(vga.config.compatible_chain4)
824 newHandler = &vgaph.cvga;
825 else
826 #ifdef VGA_LFB_MAPPED
827 newHandler = &vgaph.map;
828 #else
829 newHandler = &vgaph.changes;
830 #endif
831 } else {
832 newHandler = &vgaph.uvga;
833 }
834 break;
835 case M_EGA:
836 if (vga.config.chained)
837 newHandler = &vgaph.cega;
838 else
839 newHandler = &vgaph.uega;
840 break;
841 case M_TEXT:
842 /* Check if we're not in odd/even mode */
843 if (vga.gfx.miscellaneous & 0x2) newHandler = &vgaph.map;
844 else newHandler = &vgaph.text;
845 break;
846 case M_CGA4:
847 case M_CGA2:
848 newHandler = &vgaph.map;
849 break;
850 }
851 switch ((vga.gfx.miscellaneous >> 2) & 3) {
852 case 0:
853 vgapages.base = VGA_PAGE_A0;
854 switch (svgaCard) {
855 case SVGA_TsengET3K:
856 case SVGA_TsengET4K:
857 vgapages.mask = 0xffff;
858 break;
859 case SVGA_S3Trio:
860 default:
861 vgapages.mask = 0x1ffff;
862 break;
863 }
864 MEM_SetPageHandler(VGA_PAGE_A0, 32, newHandler );
865 break;
866 case 1:
867 vgapages.base = VGA_PAGE_A0;
868 vgapages.mask = 0xffff;
869 MEM_SetPageHandler( VGA_PAGE_A0, 16, newHandler );
870 MEM_ResetPageHandler( VGA_PAGE_B0, 16);
871 break;
872 case 2:
873 vgapages.base = VGA_PAGE_B0;
874 vgapages.mask = 0x7fff;
875 MEM_SetPageHandler( VGA_PAGE_B0, 8, newHandler );
876 MEM_ResetPageHandler( VGA_PAGE_A0, 16 );
877 MEM_ResetPageHandler( VGA_PAGE_B8, 8 );
878 break;
879 case 3:
880 vgapages.base = VGA_PAGE_B8;
881 vgapages.mask = 0x7fff;
882 MEM_SetPageHandler( VGA_PAGE_B8, 8, newHandler );
883 MEM_ResetPageHandler( VGA_PAGE_A0, 16 );
884 MEM_ResetPageHandler( VGA_PAGE_B0, 8 );
885 break;
886 }
887 if(svgaCard == SVGA_S3Trio && (vga.s3.ext_mem_ctrl & 0x10))
888 MEM_SetPageHandler(VGA_PAGE_A0, 16, &vgaph.mmio);
889 range_done:
890 PAGING_ClearTLB();
891 }
892
VGA_StartUpdateLFB(void)893 void VGA_StartUpdateLFB(void) {
894 vga.lfb.page = vga.s3.la_window << 4;
895 vga.lfb.addr = vga.s3.la_window << 16;
896 #ifdef VGA_LFB_MAPPED
897 vga.lfb.handler = &vgaph.lfb;
898 #else
899 vga.lfb.handler = &vgaph.lfbchanges;
900 #endif
901 MEM_SetLFB(vga.s3.la_window << 4 ,vga.vmemsize/4096, vga.lfb.handler, &vgaph.mmio);
902 }
903
VGA_Memory_ShutDown(Section *)904 static void VGA_Memory_ShutDown(Section * /*sec*/) {
905 delete[] vga.mem.linear_orgptr;
906 delete[] vga.fastmem_orgptr;
907 #ifdef VGA_KEEP_CHANGES
908 delete[] vga.changes.map;
909 #endif
910 }
911
VGA_SetupMemory(Section * sec)912 void VGA_SetupMemory(Section* sec) {
913 vga.svga.bank_read = vga.svga.bank_write = 0;
914 vga.svga.bank_read_full = vga.svga.bank_write_full = 0;
915
916 Bit32u vga_allocsize=vga.vmemsize;
917 // Keep lower limit at 512k
918 if (vga_allocsize<512*1024) vga_allocsize=512*1024;
919 // We reserve extra 2K for one scan line
920 vga_allocsize+=2048;
921 vga.mem.linear_orgptr = new Bit8u[vga_allocsize+16];
922 vga.mem.linear=(Bit8u*)(((Bitu)vga.mem.linear_orgptr + 16-1) & ~(16-1));
923 memset(vga.mem.linear,0,vga_allocsize);
924
925 vga.fastmem_orgptr = new Bit8u[(vga.vmemsize<<1)+4096+16];
926 vga.fastmem=(Bit8u*)(((Bitu)vga.fastmem_orgptr + 16-1) & ~(16-1));
927
928 // In most cases these values stay the same. Assumptions: vmemwrap is power of 2,
929 // vmemwrap <= vmemsize, fastmem implicitly has mem wrap twice as big
930 vga.vmemwrap = vga.vmemsize;
931
932 #ifdef VGA_KEEP_CHANGES
933 memset( &vga.changes, 0, sizeof( vga.changes ));
934 int changesMapSize = (vga.vmemsize >> VGA_CHANGE_SHIFT) + 32;
935 vga.changes.map = new Bit8u[changesMapSize];
936 memset(vga.changes.map, 0, changesMapSize);
937 #endif
938 vga.svga.bank_read = vga.svga.bank_write = 0;
939 vga.svga.bank_read_full = vga.svga.bank_write_full = 0;
940 vga.svga.bank_size = 0x10000; /* most common bank size is 64K */
941
942 sec->AddDestroyFunction(&VGA_Memory_ShutDown);
943
944 if (machine==MCH_PCJR) {
945 /* PCJr does not have dedicated graphics memory but uses
946 conventional memory below 128k */
947 //TODO map?
948 }
949 }
950