Fix EGA scrolling for modes 0x0D and 0x0E
This commit is contained in:
parent
aa98f63f47
commit
38f16fcc50
13 changed files with 3322 additions and 3077 deletions
180
blog/2015/06/05/README.md
Normal file
180
blog/2015/06/05/README.md
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
The Strange Case of the EGA Graphics Scroll Bug
|
||||
---
|
||||
|
||||
For reasons I've forgotten, I was playing with different video modes in this
|
||||
[IBM PC AT w/EGA](/devices/pc/machine/5170/ega/640kb/rev1/) machine, and I discovered some odd problems.
|
||||
|
||||
For example, run this code:
|
||||
|
||||
A>b:debug
|
||||
-a
|
||||
0CE0:0100 mov ax,e
|
||||
0CE0:0103 int 10
|
||||
0CE0:0105 int 3
|
||||
0CE0:0106
|
||||
-g
|
||||
|
||||
and the following "text" will appear at the top of the screen, in 640x200 16-color graphics mode 0x0E:
|
||||
|
||||
AX=0B01 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
|
||||
DS=0CE0 ES=0CE0 SS=0CE0 CS=0CE0 IP=0105 NV UP EI PL NZ NA PO NC
|
||||
0CE0:0105 CC INT 3
|
||||
-
|
||||
|
||||
If I typed "q", then "cls" and finally "dir", the screen would properly fill with DOS directory contents.
|
||||
However, as soon as the screen started to scroll, the screen contents became garbled. Other EGA graphics modes,
|
||||
like 640x350 16-color mode 0x10, didn't have this problem.
|
||||
|
||||
To investigate, I set a breakpoint in the IBM EGA ROM where the scrolling starts, at 0xC000:12EA (see p.130 of the
|
||||
"IBM Enhanced Graphics Adapter" Technical Reference document):
|
||||
|
||||
CRANK_A:
|
||||
PUSH CX
|
||||
MOV CL,DL
|
||||
SUB CH,CH
|
||||
PUSH SI
|
||||
PUSH DI
|
||||
REP MOVSB
|
||||
POP DI
|
||||
POP SI
|
||||
ADD SI,BX
|
||||
ADD DI,BX
|
||||
POP CX
|
||||
LOOP CRANK_A
|
||||
|
||||
CX arrives as 0xC0 (192), which is the number of scan-lines to move up, and BX is 0x50 (80), the number
|
||||
of bytes per scan-line.
|
||||
|
||||
When the breakpoint was hit, I dumped the video hardware state, using the Debugger's "*d video*" command.
|
||||
For reference purposes, I've pasted the corresponding video state for mode 0x10 on the right-hand side.
|
||||
|
||||
breakpoint hit: C000:12EA (exec)
|
||||
stopped (175707689 ops, 800060264 cycles, 133470 ms, 5994308 hz)
|
||||
AX=020F BX=0050 CX=00C0 DX=1950 SP=0B58 BP=0511 SI=0280 DI=0000
|
||||
SS=011F DS=A000 ES=A000 PS=0246 V0 D0 I1 T0 S0 Z1 A0 P1 C0
|
||||
C000:12EA 51 PUSH CX
|
||||
|
||||
BIOSMODE: 0x0E BIOSMODE: 0x10
|
||||
CRTC[0x00]: HORZ_TOTAL 0x70 CRTC[0x00]: HORZ_TOTAL 0x5B
|
||||
CRTC[0x01]: HORZ_DISP_END 0x4F CRTC[0x01]: HORZ_DISP_END 0x4F
|
||||
CRTC[0x02]: HORZ_BLANK_START 0x59 CRTC[0x02]: HORZ_BLANK_START 0x53
|
||||
CRTC[0x03]: HORZ_BLANK_END 0x2D CRTC[0x03]: HORZ_BLANK_END 0x37
|
||||
CRTC[0x04]: HORZ_RETRACE_START 0x5E CRTC[0x04]: HORZ_RETRACE_START 0x52
|
||||
CRTC[0x05]: HORZ_RETRACE_END 0x06 CRTC[0x05]: HORZ_RETRACE_END 0x00
|
||||
CRTC[0x06]: VERT_TOTAL 0x04 CRTC[0x06]: VERT_TOTAL 0x6C
|
||||
CRTC[0x07]: OVERFLOW 0x11 CRTC[0x07]: OVERFLOW 0x1F
|
||||
CRTC[0x08]: PRESET_ROW_SCAN 0x00 CRTC[0x08]: PRESET_ROW_SCAN 0x00
|
||||
CRTC[0x09]: MAX_SCAN_LINE 0x00 CRTC[0x09]: MAX_SCAN_LINE 0x00
|
||||
CRTC[0x0A]: CURSOR_START 0x00 CRTC[0x0A]: CURSOR_START 0x00
|
||||
CRTC[0x0B]: CURSOR_END 0x01 CRTC[0x0B]: CURSOR_END 0x01
|
||||
CRTC[0x0C]: START_ADDR_HI 0x00 CRTC[0x0C]: START_ADDR_HI 0x00
|
||||
CRTC[0x0D]: START_ADDR_LO 0x00 CRTC[0x0D]: START_ADDR_LO 0x00
|
||||
CRTC[0x0E]: CURSOR_ADDR_HI 0x07 CRTC[0x0E]: CURSOR_ADDR_HI 0x01
|
||||
CRTC[0x0F]: CURSOR_ADDR_LO 0x80* CRTC[0x0F]: CURSOR_ADDR_LO 0x41*
|
||||
CRTC[0x10]: VERT_RETRACE_START 0xE0 CRTC[0x10]: VERT_RETRACE_START 0x5E
|
||||
CRTC[0x11]: VERT_RETRACE_END 0x23 CRTC[0x11]: VERT_RETRACE_END 0x2B
|
||||
CRTC[0x12]: VERT_DISP_END 0xC7 CRTC[0x12]: VERT_DISP_END 0x5D
|
||||
CRTC[0x13]: OFFSET 0x28 CRTC[0x13]: OFFSET 0x28
|
||||
CRTC[0x14]: UNDERLINE 0x00 CRTC[0x14]: UNDERLINE 0x0F
|
||||
CRTC[0x15]: VERT_BLANK_START 0xDF CRTC[0x15]: VERT_BLANK_START 0x5F
|
||||
CRTC[0x16]: VERT_BLANK_END 0xEF CRTC[0x16]: VERT_BLANK_END 0x0A
|
||||
CRTC[0x17]: MODE_CTRL 0xE3 CRTC[0x17]: MODE_CTRL 0xE3
|
||||
CRTC[0x18]: LINE_COMPARE 0xFF CRTC[0x18]: LINE_COMPARE 0xFF
|
||||
STATUS1: 0x01 STATUS1: 0x01
|
||||
ATCDATA: true ATCDATA: true
|
||||
ATC[0x00]: PAL00 0x00 ATC[0x00]: PAL00 0x00
|
||||
ATC[0x01]: PAL01 0x01 ATC[0x01]: PAL01 0x01
|
||||
ATC[0x02]: PAL02 0x02 ATC[0x02]: PAL02 0x02
|
||||
ATC[0x03]: PAL03 0x03 ATC[0x03]: PAL03 0x03
|
||||
ATC[0x04]: PAL04 0x04 ATC[0x04]: PAL04 0x04
|
||||
ATC[0x05]: PAL05 0x05 ATC[0x05]: PAL05 0x05
|
||||
ATC[0x06]: PAL06 0x06 ATC[0x06]: PAL06 0x14
|
||||
ATC[0x07]: PAL07 0x07 ATC[0x07]: PAL07 0x07
|
||||
ATC[0x08]: PAL08 0x10 ATC[0x08]: PAL08 0x38
|
||||
ATC[0x09]: PAL09 0x11 ATC[0x09]: PAL09 0x39
|
||||
ATC[0x0A]: PAL0A 0x12 ATC[0x0A]: PAL0A 0x3A
|
||||
ATC[0x0B]: PAL0B 0x13 ATC[0x0B]: PAL0B 0x3B
|
||||
ATC[0x0C]: PAL0C 0x14 ATC[0x0C]: PAL0C 0x3C
|
||||
ATC[0x0D]: PAL0D 0x15 ATC[0x0D]: PAL0D 0x3D
|
||||
ATC[0x0E]: PAL0E 0x16 ATC[0x0E]: PAL0E 0x3E
|
||||
ATC[0x0F]: PAL0F 0x17 ATC[0x0F]: PAL0F 0x3F
|
||||
ATC[0x10]: MODE 0x01 ATC[0x10]: MODE 0x01
|
||||
ATC[0x11]: OVERSCAN 0x00 ATC[0x11]: OVERSCAN 0x00
|
||||
ATC[0x12]: PLANES 0x0F ATC[0x12]: PLANES 0x0F
|
||||
ATC[0x13]: HORZPAN 0x00 ATC[0x13]: HORZPAN 0x00
|
||||
GRC[0x00]: SRESET 0x00 GRC[0x00]: SRESET 0x00
|
||||
GRC[0x01]: ESRESET 0x00 GRC[0x01]: ESRESET 0x00
|
||||
GRC[0x02]: COLORCMP 0x00 GRC[0x02]: COLORCMP 0x00
|
||||
GRC[0x03]: DATAROT 0x00 GRC[0x03]: DATAROT 0x00*
|
||||
GRC[0x04]: READMAP 0x00 GRC[0x04]: READMAP 0x00
|
||||
GRC[0x05]: MODE 0x11* GRC[0x05]: MODE 0x00
|
||||
GRC[0x06]: MISC 0x05 GRC[0x06]: MISC 0x05
|
||||
GRC[0x07]: COLORDC 0x0F GRC[0x07]: COLORDC 0x0F
|
||||
GRC[0x08]: BITMASK 0xFF GRC[0x08]: BITMASK 0xFF
|
||||
SEQ[0x00]: RESET 0x03 SEQ[0x00]: RESET 0x03
|
||||
SEQ[0x01]: CLOCKING 0x01 SEQ[0x01]: CLOCKING 0x01
|
||||
SEQ[0x02]: MAPMASK 0x0F* SEQ[0x02]: MAPMASK 0x0F*
|
||||
SEQ[0x03]: CHARMAP 0x00 SEQ[0x03]: CHARMAP 0x00
|
||||
SEQ[0x04]: MEMMODE 0x06 SEQ[0x04]: MEMMODE 0x06
|
||||
FEAT: 0x02 FEAT: 0x02
|
||||
MISC: 0x23 MISC: 0xA7
|
||||
STATUS0: 0x10 STATUS0: 0x10
|
||||
LATCHES: 0x00000000 LATCHES: 0x00000000
|
||||
ACCESS: 0x1411 ACCESS: 0x0400
|
||||
|
||||
One of the apparent oddities is that, for mode 0x0E, GRC[MODE] has been programmed with 0x11, whereas
|
||||
for mode 0x10, it was programmed with 0x00. Why would mode 0x0E want to set the ODDEVEN bit during the scroll,
|
||||
when it hadn't been set during any other writes to the screen?
|
||||
|
||||
At this point, I dumped the instruction history buffer a bit ("*dh 100*"), and noticed this GRC write:
|
||||
|
||||
C000:1582 8BC5 MOV AX,BP ;history=33
|
||||
C000:1584 B603 MOV DH,03 ;history=32
|
||||
C000:1586 B2CE MOV DL,CE ;history=31
|
||||
C000:1588 E88AF7 CALL 0D15 ;history=30
|
||||
C000:0D15 86C4 XCHG AL,AH ;history=29
|
||||
C000:0D17 EE OUT DX,AL ;history=28
|
||||
C000:0D18 42 INC DX ;history=27
|
||||
C000:0D19 86C4 XCHG AL,AH ;history=26
|
||||
C000:0D1B EE OUT DX,AL ;history=25
|
||||
C000:0D1C 4A DEC DX ;history=24
|
||||
|
||||
So I looked back farther and saw where BP was set:
|
||||
|
||||
C000:1522 BA00A0 MOV DX,A000 ;history=97
|
||||
C000:1525 BD1105 MOV BP,0511 ;history=96
|
||||
|
||||
Here's the complete function:
|
||||
|
||||
GR_ST_1:
|
||||
MOV DX,A000
|
||||
MOV BP,0511
|
||||
CMP AH,0F
|
||||
JC 1535
|
||||
CALL 14F7
|
||||
JNC 1535
|
||||
MOV BP,0501
|
||||
RET
|
||||
|
||||
OK, so any (EGA) graphics mode below 0x0F is going to the trigger the use of Write Mode 1 with the ODDEVEN bit set.
|
||||
And sure enough, the scrolling bug also occurs when using 320x200 16-color mode 0x0D.
|
||||
|
||||
It's also worth noting that, whenver the ODDEVEN bit of the GRC Mode Register is set, the SEQUENTIAL bit in the Sequencer
|
||||
Memory Mode Register is supposed to be clear (and vice versa -- those two bits are always supposed to be oppositely set).
|
||||
But here, the IBM EGA BIOS hasn't done that. One wonders if that was a mistake....
|
||||
|
||||
Another bit of trivia: while dumping the frame buffer in a VGA text mode in a different emulator, I discovered that
|
||||
if I turned off the ODDEVEN bit in the GRC Mode Register, odd bytes would still appear from plane 1; it wasn't until I
|
||||
*also* turned off the CHAIN bit in the GRC Miscellaneous Register that the odd bytes would no longer appear. But,
|
||||
that could have just been an idiosyncrasy of that particular emulator.
|
||||
|
||||
As a result of all these observations, and more importantly, to make EGA scrolling work properly in modes 0x0D and 0x0E,
|
||||
I've changed the Video component to use odd/even memory functions *only* when the SEQUENTIAL bit (bit 2) of the
|
||||
Sequencer's Memory Mode Register is clear, instead of relying on the ODDEVEN bit (bit 4) of the Graphics Controller's Mode
|
||||
Register.
|
||||
|
||||
To be continued.... because I've barely scratched the surface of all the side-effects of EGA/VGA odd/even addressing,
|
||||
and I hope to do some testing on real hardware in the near future.
|
||||
|
||||
*[@jeffpar](http://twitter.com/jeffpar)*
|
||||
*June 5, 2015*
|
||||
|
|
@ -1,12 +1,18 @@
|
|||
IBM PC Machine Configurations
|
||||
---
|
||||
|
||||
Here you'll find sample Machine Configurations for all the IBM PC models that PCjs currently supports.
|
||||
PCjs supports the following IBM PC models:
|
||||
|
||||
* [Model 5150](/devices/pc/machine/#model-5150-machine-configurations)
|
||||
* [Model 5160](/devices/pc/machine/#model-5160-machine-configurations)
|
||||
* [Model 5170](/devices/pc/machine/#model-5170-machine-configurations)
|
||||
|
||||
Configurations for the [Challenger 1P](/devices/c1p/machine/) and other non-IBM machines are available [here](/devices/).
|
||||
|
||||
Support is also being added for a few IBM PC-compatible machines, starting with the [Compaq DeskPro 386](compaq/deskpro386/) series.
|
||||
|
||||
---
|
||||
|
||||
### Model 5150 Machine Configurations
|
||||
|
||||
* [IBM PC, MDA, 64K](/devices/pc/machine/5150/mda/64kb/)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -240,6 +240,8 @@ var asFilesNonServed = [
|
|||
"web.config" // Azure/IISNode-specific
|
||||
];
|
||||
|
||||
var nBlogExcerpts = 20;
|
||||
|
||||
/**
|
||||
* HTMLOut()
|
||||
*
|
||||
|
|
@ -1167,10 +1169,10 @@ HTMLOut.prototype.getBlog = function(sToken, sIndent, aParms)
|
|||
* strings) that can hold the excerpts. We'll plug the excerpts into aExcerpts as they
|
||||
* come in, and then we'll assemble them all at the end.
|
||||
*
|
||||
* We also take this opportunity to cap the number of (most recent) excerpts at 10.
|
||||
* We also take this opportunity to cap the number of (most recent) excerpts.
|
||||
*/
|
||||
var i;
|
||||
var cExcerpts = Math.min(asPaths.length, 10);
|
||||
var cExcerpts = Math.min(asPaths.length, nBlogExcerpts);
|
||||
var aExcerpts = new Array(cExcerpts);
|
||||
var cExcerptsRemaining = aExcerpts.length;
|
||||
for (i = 0; i < cExcerpts; i++) {
|
||||
|
|
|
|||
|
|
@ -4499,7 +4499,7 @@ if (DEBUGGER) {
|
|||
this.println("\ninput commands:");
|
||||
this.println("\ti [p]\tread port [p]");
|
||||
/*
|
||||
* NOTE: Regarding this warning, it might be nice if we had an "unchecked" version of
|
||||
* TODO: Regarding this warning, consider adding an "unchecked" version of
|
||||
* bus.checkPortInputNotify(), since all Debugger memory accesses are unchecked, too.
|
||||
*
|
||||
* All port I/O handlers ARE aware when the Debugger is calling (addrFrom is undefined),
|
||||
|
|
@ -4796,7 +4796,7 @@ if (DEBUGGER) {
|
|||
this.println("\noutput commands:");
|
||||
this.println("\to [p] [b]\twrite byte [b] to port [p]");
|
||||
/*
|
||||
* NOTE: Regarding this warning, it might be nice if we had an "Unchecked" version of
|
||||
* TODO: Regarding this warning, consider adding an "unchecked" version of
|
||||
* bus.checkPortOutputNotify(), since all Debugger memory accesses are unchecked, too.
|
||||
*
|
||||
* All port I/O handlers ARE aware when the Debugger is calling (addrFrom is undefined),
|
||||
|
|
|
|||
|
|
@ -1342,7 +1342,7 @@ Card.SEQ = {
|
|||
SELB_HIGH: 0x10, // VGA only
|
||||
SELA_HIGH: 0x20 // VGA only
|
||||
},
|
||||
MODE: {
|
||||
MEMMODE: {
|
||||
INDX: 0x04, // Sequencer Memory Mode Register
|
||||
ALPHA: 0x01, // set for alphanumeric (A/N) mode, clear for graphics (APA or "All Points Addressable") mode (EGA only)
|
||||
EXT: 0x02, // set if memory expansion installed, clear if not installed
|
||||
|
|
@ -1352,7 +1352,7 @@ Card.SEQ = {
|
|||
TOTAL_REGS: 0x05
|
||||
};
|
||||
|
||||
if (DEBUGGER) Card.SEQ.REGS = ["RESET","CLOCKING","MAPMASK","CHARMAP","MODE"];
|
||||
if (DEBUGGER) Card.SEQ.REGS = ["RESET","CLOCKING","MAPMASK","CHARMAP","MEMMODE"];
|
||||
|
||||
/*
|
||||
* VGA Digital-to-Analog Converter (DAC) Registers (regDACMask, regDACState, regDACAddr, and regDACData)
|
||||
|
|
@ -1507,8 +1507,8 @@ if (DEBUGGER) Card.GRC.REGS = ["SRESET","ESRESET","COLORCMP","DATAROT","READMAP"
|
|||
*
|
||||
* Even/Odd Memory Access Functions
|
||||
*
|
||||
* The "EVENODD" functions deal with the EGA's default text-mode addressing, where every EVEN address is mapped to
|
||||
* plane 0 (and plane 2) and every ODD address is mapped to plane 1 (and plane 3). This occurs when SEQ.MODE.SEQUENTIAL
|
||||
* The "EVENODD" functions deal with the EGA's default text-mode addressing, where EVEN addresses are mapped to
|
||||
* plane 0 (and 2) and ODD addresses are mapped to plane 1 (and 3). This occurs when SEQ.MEMMODE.SEQUENTIAL
|
||||
* is clear (and GRC.MODE.EVENODD is set), turning address bit 0 (A0) into a "plane select" bit. Whether A0 is
|
||||
* also used as a memory address bit depends on CRTC.MODE_CTRL.BM: if it's set, then we're in "Byte Mode" and A0 is
|
||||
* used as-is; if it's clear, then we're in "Word Mode", and either A15 (when CRTC.MODE_CTRL.AW is set) or A13
|
||||
|
|
@ -1599,6 +1599,11 @@ Card.ACCESS.readByteMode0 = function readByteMode0(off, addr)
|
|||
*/
|
||||
Card.ACCESS.readByteMode0EvenOdd = function readByteMode0EvenOdd(off, addr)
|
||||
{
|
||||
/*
|
||||
* TODO: As discussed in getAccess(), we need to run some tests on real EGA/VGA hardware to determine
|
||||
* exactly what gets latched (ie, from which address) when EVENODD is in effect. Whatever we learn may
|
||||
* also dictate a special EVENODD function for Read Mode 1 as well.
|
||||
*/
|
||||
off += this.offset;
|
||||
var idw = off & ~0x1;
|
||||
var dw = this.controller.latches = this.adw[idw];
|
||||
|
|
@ -1821,6 +1826,10 @@ Card.ACCESS.writeByteMode1 = function writeByteMode1(off, b, addr)
|
|||
*/
|
||||
Card.ACCESS.writeByteMode1EvenOdd = function writeByteMode1EvenOdd(off, b, addr)
|
||||
{
|
||||
/*
|
||||
* TODO: As discussed in getAccess(), we need to run some tests on real EGA/VGA hardware to determine
|
||||
* exactly where latches are written (ie, to which address) when EVENODD is in effect.
|
||||
*/
|
||||
off += this.offset;
|
||||
//
|
||||
// When even/odd addressing is enabled, nWriteMapMask must be cleared for planes 1 and 3 if
|
||||
|
|
@ -2225,9 +2234,9 @@ Card.prototype.dumpCard = function()
|
|||
this.dumpRegs(" FEAT", this.regFeat);
|
||||
this.dumpRegs(" MISC", this.regMisc);
|
||||
this.dumpRegs(" STATUS0", this.regStatus0);
|
||||
this.dumpRegs(" LATCHES", this.latches);
|
||||
this.dbg.println(" LATCHES: 0x" + str.toHex(this.latches));
|
||||
this.dbg.println(" ACCESS: " + str.toHexWord(this.nAccess));
|
||||
this.dbg.println("Use 'dump video buffer' to dump video memory");
|
||||
this.dbg.println("Use 'dump video [addr]' to dump video memory");
|
||||
/*
|
||||
* There are few more EGA regs we could dump, like GRCPos1, GRCPos2, but does anyone care?
|
||||
*/
|
||||
|
|
@ -3836,9 +3845,38 @@ Video.prototype.getAccess = function()
|
|||
if (regGRCMode & Card.GRC.MODE.READ_MODE1) {
|
||||
nReadAccess = Card.ACCESS.READ.MODE1;
|
||||
}
|
||||
if (regGRCMode & Card.GRC.MODE.EVENODD) {
|
||||
nReadAccess |= Card.ACCESS.READ.EVENODD;
|
||||
nWriteAccess |= Card.ACCESS.WRITE.EVENODD;
|
||||
/*
|
||||
* I discovered that when the IBM EGA ROM scrolls the screen in graphics modes 0x0D and 0x0E, it
|
||||
* reprograms this register for WRITE_MODE1 (which is fine) *and* EVENODD (which is, um, very odd).
|
||||
* Moreover, it does NOT make the complementary change to the SEQ.MEMMODE.SEQUENTIAL bit; under
|
||||
* "normal" circumstances, those two bits are always supposed to programmed oppositely.
|
||||
*
|
||||
* Until I can perform some tests on real hardware, I have to assume that the EGA scroll operation
|
||||
* is supposed to actually WORK in modes 0x0D and 0x0E, so I've decided to tie the trigger for my own
|
||||
* EVENODD functions to SEQ.MEMMODE.SEQUENTIAL being clear, instead of GRC.MODE.EVENODD being set.
|
||||
*
|
||||
* It's also possible that my EVENODD read/write functions are not implemented properly; when EVENODD
|
||||
* is in effect, which addresses get latched by a read, and to which addresses are latches written?
|
||||
* If EVENODD has no effect on the effective address used with the latches, then I should change the
|
||||
* EVENODD read/write functions accordingly.
|
||||
*
|
||||
* However, I've also done some limited testing with an emulated VGA running in text mode, and I've
|
||||
* discovered that toggling the GRC.MODE.EVENODD bit *alone* doesn't seem to affect the delivery of
|
||||
* text mode attributes from plane 1. So maybe this is the wiser change after all.
|
||||
*
|
||||
* TODO: Perform some tests on actual EGA/VGA hardware, to determine the proper course of action.
|
||||
*
|
||||
* if (regGRCMode & Card.GRC.MODE.EVENODD) {
|
||||
* nReadAccess |= Card.ACCESS.READ.EVENODD;
|
||||
* nWriteAccess |= Card.ACCESS.WRITE.EVENODD;
|
||||
* }
|
||||
*/
|
||||
var regSEQMode = card.regSEQData[Card.SEQ.MEMMODE.INDX];
|
||||
if (regSEQMode != null) {
|
||||
if (!(regSEQMode & Card.SEQ.MEMMODE.SEQUENTIAL)) {
|
||||
nReadAccess |= Card.ACCESS.READ.EVENODD;
|
||||
nWriteAccess |= Card.ACCESS.WRITE.EVENODD;
|
||||
}
|
||||
}
|
||||
nAccess = nReadAccess | nWriteAccess;
|
||||
}
|
||||
|
|
@ -5157,8 +5195,15 @@ Video.prototype.outSEQData = function(port, bOut, addrFrom)
|
|||
}
|
||||
this.cardEGA.regSEQData[this.cardEGA.regSEQIndx] = bOut;
|
||||
}
|
||||
if (this.cardEGA.regSEQIndx == Card.SEQ.MAPMASK.INDX) {
|
||||
switch(this.cardEGA.regSEQIndx) {
|
||||
case Card.SEQ.MAPMASK.INDX:
|
||||
this.cardEGA.nWriteMapMask = Video.aEGAByteToDW[bOut & Card.SEQ.MAPMASK.MAPS];
|
||||
break;
|
||||
case Card.SEQ.MEMMODE.INDX:
|
||||
this.setAccess(this.getAccess());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/apps/pc/">Apps</a></li>
|
||||
<li><a href="/disks/pc/">Disks</a></li>
|
||||
<li><a href="/devices/">Machines</a></li>
|
||||
<li><a href="/devices/pc/machine/">Machines</a></li>
|
||||
<li><a href="/docs/">Docs</a></li>
|
||||
<li><a href="/pubs/">Pubs</a></li>
|
||||
<li><a href="/blog/">Blog</a></li>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/apps/pc/">Apps</a></li>
|
||||
<li><a href="/disks/pc/">Disks</a></li>
|
||||
<li><a href="/devices/">Machines</a></li>
|
||||
<li><a href="/devices/pc/machine/">Machines</a></li>
|
||||
<li><a href="/docs/">Docs</a></li>
|
||||
<li><a href="/pubs/">Pubs</a></li>
|
||||
<li><a href="/blog/">Blog</a></li>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/apps/pc/">Apps</a></li>
|
||||
<li><a href="/disks/pc/">Disks</a></li>
|
||||
<li><a href="/devices/">Machines</a></li>
|
||||
<li><a href="/devices/pc/machine/">Machines</a></li>
|
||||
<li><a href="/docs/">Docs</a></li>
|
||||
<li><a href="/pubs/">Pubs</a></li>
|
||||
<li><a href="/blog/">Blog</a></li>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/apps/pc/">Apps</a></li>
|
||||
<li><a href="/disks/pc/">Disks</a></li>
|
||||
<li><a href="/devices/">Machines</a></li>
|
||||
<li><a href="/devices/pc/machine/">Machines</a></li>
|
||||
<li><a href="/docs/">Docs</a></li>
|
||||
<li><a href="/pubs/">Pubs</a></li>
|
||||
<li><a href="/blog/">Blog</a></li>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue