Fix EGA scrolling for modes 0x0D and 0x0E

This commit is contained in:
Jeff Parsons 2015-06-05 17:26:08 -07:00
commit 38f16fcc50
13 changed files with 3322 additions and 3077 deletions

View file

@ -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++) {

View file

@ -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),

View file

@ -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;
}
};

View file

@ -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>

View file

@ -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>