Minor VGA updates

This commit is contained in:
Jeff Parsons 2015-05-28 14:28:00 -07:00
commit 7b715cf306

View file

@ -915,7 +915,7 @@ function Card(video, iCard, data, cbMemory)
this.port = specs[1]; this.port = specs[1];
} }
this.iCard = iCard; this.nCard = iCard;
this.addrBuffer = specs[2]; // default (physical) frame buffer address this.addrBuffer = specs[2]; // default (physical) frame buffer address
this.sizeBuffer = specs[3]; // default frame buffer length (this is the total size, not the current visible size; this.cbScreen is calculated on the fly to reflect the latter) this.sizeBuffer = specs[3]; // default frame buffer length (this is the total size, not the current visible size; this.cbScreen is calculated on the fly to reflect the latter)
@ -1135,12 +1135,17 @@ if (DEBUGGER) {
Card.CRTC.EGA_REGS = ["HORZ_TOTAL","HORZ_DISP_END","HORZ_BLANK_START","HORZ_BLANK_END","HORZ_RETRACE_START","HORZ_RETRACE_END", Card.CRTC.EGA_REGS = ["HORZ_TOTAL","HORZ_DISP_END","HORZ_BLANK_START","HORZ_BLANK_END","HORZ_RETRACE_START","HORZ_RETRACE_END",
"VERT_TOTAL","CRTC_OVERFLOW","PRESET_ROW_SCAN","MAX_SCAN_LINE","CURSOR_START","CURSOR_END", "VERT_TOTAL","CRTC_OVERFLOW","PRESET_ROW_SCAN","MAX_SCAN_LINE","CURSOR_START","CURSOR_END",
"START_ADDR_HI","START_ADDR_LO","CURSOR_ADDR_HI","CURSOR_ADDR_LO","LIGHT_PEN_HI","LIGHT_PEN_LO", "START_ADDR_HI","START_ADDR_LO","CURSOR_ADDR_HI","CURSOR_ADDR_LO","LIGHT_PEN_HI","LIGHT_PEN_LO",
"VERT_DISP_END","OFFSET","UNDERLINE","VERT_BLANK_START","VERT_BLANK_END","MODE_CTRL","LONE_COMPARE"]; "VERT_DISP_END","OFFSET","UNDERLINE","VERT_BLANK_START","VERT_BLANK_END","MODE_CTRL","LINE_COMPARE"];
} }
/* /*
* EGA/VGA Input Status 1 Register * EGA/VGA Input Status 1 Register
* *
* STATUS1 bit 0 has confusing documentation: the EGA Tech Ref says "Logical 0 indicates the CRT raster is in a
* horizontal or vertical retrace interval", whereas the VGA Tech Ref says "Logical 1 indicates a horizontal or
* vertical retrace interval." The name of the status bit suggests that the EGA is right and the VGA is wrong,
* but this needs to be confirmed.
*
* STATUS1 diagnostic bits 5 and 4 are set according to the Card.ATC.PLANES.MUX bits: * STATUS1 diagnostic bits 5 and 4 are set according to the Card.ATC.PLANES.MUX bits:
* *
* MUX Bit 5 Bit 4 * MUX Bit 5 Bit 4
@ -1152,7 +1157,10 @@ if (DEBUGGER) {
*/ */
Card.STATUS1 = { Card.STATUS1 = {
PORT: 0x3DA, PORT: 0x3DA,
DIAGNOSTIC: 0x30 // these bits are controlled by the Card.ATC.PLANES.MUX bits DISP_ENABLED: 0x01, // bit 0: logical OR of horizontal and vertical retrace states
VERT_RETRACE: 0x08, // bit 3: set during vertical retrace interval
DIAGNOSTIC: 0x30, // bits 5,4 are controlled by the Card.ATC.PLANES.MUX bits
RESERVED: 0xC6
}; };
/* /*
@ -1225,6 +1233,20 @@ if (DEBUGGER) {
"MODE","OVRSCAN","PLANES","HORZPAN"]; "MODE","OVRSCAN","PLANES","HORZPAN"];
} }
/*
* EGA/VGA Feature Control Register (regFeat)
*
* The EGA BIOS writes 0x1 to Card.FEAT_CTRL.BITS and reads Card.STATUS0.FEAT, then writes 0x2 to
* Card.FEAT_CTRL.BITS and reads Card.STATUS0.FEAT. The bits from the first and second reads are shifted
* into the high nibble of the byte at 40:88h.
*/
Card.FEAT_CTRL = {
PORT_MONO: 0x3BA, // write port address (other than the two bits below, the rest are reserved and/or unused)
PORT_COLOR: 0x3DA, // write port address (other than the two bits below, the rest are reserved and/or unused)
PORT_READ: 0x3CA, // read port address (VGA only)
BITS: 0x03 // feature control bits
};
/* /*
* EGA/VGA Miscellaneous Output Register (regMisc) * EGA/VGA Miscellaneous Output Register (regMisc)
*/ */
@ -1240,20 +1262,6 @@ Card.MISC = {
VERT_POLARITY: 0x80 // 0 selects positive vertical retrace VERT_POLARITY: 0x80 // 0 selects positive vertical retrace
}; };
/*
* EGA/VGA Feature Control Register (regFeat)
*
* The EGA BIOS writes 0x1 to Card.FEAT_CTRL.BITS and reads Card.STATUS0.FEAT, then writes 0x2 to
* Card.FEAT_CTRL.BITS and reads Card.STATUS0.FEAT. The bits from the first and second reads are shifted
* into the high nibble of the byte at 40:88h.
*/
Card.FEAT_CTRL = {
PORT_MONO: 0x3BA, // write port address (other than the two bits below, the rest are reserved and/or unused)
PORT_COLOR: 0x3DA, // write port address (other than the two bits below, the rest are reserved and/or unused)
PORT_READ: 0x3CA, // read port address (VGA only)
BITS: 0x03 // feature control bits
};
/* /*
* EGA/VGA Input Status 0 Register (regStatus0) * EGA/VGA Input Status 0 Register (regStatus0)
*/ */
@ -1281,18 +1289,18 @@ Card.VGA_ENABLE = {
Card.SEQ = { Card.SEQ = {
INDX: { INDX: {
PORT: 0x3C4, PORT: 0x3C4,
MASK: 0x1F MASK: 0x07
}, },
DATA: { DATA: {
PORT: 0x3C5 PORT: 0x3C5
}, },
RESET: { RESET: {
INDX: 0x00, // RESET INDX: 0x00, // Sequencer Reset Register
ASYNC: 0x01, ASYNC: 0x01,
SYNC: 0x02 SYNC: 0x02
}, },
CLK: { CLK: {
INDX: 0x01, // CLOCKING MODE INDX: 0x01, // Sequencer Clocking Mode Register
DOTS8: 0x01, // 1: 8 dots; 0: 9 dots DOTS8: 0x01, // 1: 8 dots; 0: 9 dots
BANDWIDTH: 0x02, // 0: CRTC has access 4 out of every 5 cycles (for high-res modes); 1: CRTC has access 2 out of 5 (VGA: reserved) BANDWIDTH: 0x02, // 0: CRTC has access 4 out of every 5 cycles (for high-res modes); 1: CRTC has access 2 out of 5 (VGA: reserved)
SHIFTLOAD: 0x04, SHIFTLOAD: 0x04,
@ -1302,23 +1310,27 @@ Card.SEQ = {
RESERVED: 0xC0 RESERVED: 0xC0
}, },
MAPMASK: { MAPMASK: {
INDX: 0x02, // MAP MASK INDX: 0x02, // Sequencer Map Mask Register
PL0: 0x01, PL0: 0x01,
PL1: 0x02, PL1: 0x02,
PL2: 0x04, PL2: 0x04,
PL3: 0x08, PL3: 0x08,
MAPS: 0x0f MAPS: 0x0F,
RESERVED: 0xF0
}, },
CHARMAP: { CHARMAP: {
INDX: 0x03, // CHAR MAP SELECT INDX: 0x03, // Sequencer Character Map Select Register
SELB: 0x03, // 0x0: 1st 8Kb of plane 2; 0x1: 2nd 8Kb; 0x2: 3rd 8Kb; 0x3: 4th 8Kb SELB: 0x03, // 0x0: 1st 8Kb of plane 2; 0x1: 2nd 8Kb; 0x2: 3rd 8Kb; 0x3: 4th 8Kb
SELA: 0x0C // 0x0: 1st 8Kb of plane 2; 0x4: 2nd 8Kb; 0x8: 3rd 8Kb; 0xC: 4th 8Kb SELA: 0x0C, // 0x0: 1st 8Kb of plane 2; 0x4: 2nd 8Kb; 0x8: 3rd 8Kb; 0xC: 4th 8Kb
SELB_HIGH: 0x10, // VGA only
SELA_HIGH: 0x20 // VGA only
}, },
MODE: { MODE: {
INDX: 0x04, // MEMORY MODE INDX: 0x04, // Sequencer Memory Mode Register
ALPHA: 0x01, // 1: alphanumeric (A/N) mode active; 0: graphics (APA or "All Points Addressable") mode active ALPHA: 0x01, // set for alphanumeric (A/N) mode, clear for graphics (APA or "All Points Addressable") mode (EGA only)
EXT: 0x02, // 1: memory expansion installed; 0: not installed EXT: 0x02, // set if memory expansion installed, clear if not installed
SEQUENTIAL: 0x04 // 1: memory is sequential; 0: even addresses mapped to planes 0/2, odd addresses to planes 1/3 SEQUENTIAL: 0x04, // set for sequential memory access, clear for mapping even addresses to planes 0/2, odd addresses to planes 1/3
CHAIN4: 0x08 // VGA only: set to select memory map (plane) based on low 2 bits of address
}, },
TOTAL_REGS: 0x05 TOTAL_REGS: 0x05
}; };
@ -1839,21 +1851,19 @@ Card.ACCESS.afn[Card.ACCESS.WRITE.MODE2XOR] = Card.ACCESS.writeByteMode2Xor;
* arrays of nulls, which means that any uninitialized register arrays whose elements were all originally * arrays of nulls, which means that any uninitialized register arrays whose elements were all originally
* undefined come back via the JSON round-trip as *initialized* arrays whose elements are now all null. * undefined come back via the JSON round-trip as *initialized* arrays whose elements are now all null.
* *
* I'm a bit surprised, because JavaScript purists want us to use the '===' operator to determine * I'm a bit surprised, because JavaScript purists tell us to always use the '===' operator (eg, use
* whether an element is initialized (eg, 'aReg[i] === undefined'), but because of this JSON stupidity, * 'aReg[i] === undefined' to determine if an element is initialized), but because of this JSON stupidity,
* that would require all such tests to become 'aReg[i] === undefined || aReg[i] === null'. Great. * that would require all such tests to become 'aReg[i] === undefined || aReg[i] === null'. I'm puzzled
* why the coercion of '==' is considered evil but JSON's coercion of undefined to null is perfectly fine.
* *
* The simple solution is to change such comparisons to 'aReg[i] == null', because undefined is coerced * The simple solution is to change such comparisons to 'aReg[i] == null', because undefined is coerced
* to null, whereas numeric values are not. * to null, whereas numeric values are not.
* *
* Someday, perhaps a purist can explain to me why the coercion of '==' is evil, but JSON's coercion of
* 'undefined' values to 'null' values is not.
*
* [What do I mean by "another" frustration? Let me talk to you some day about disallowing hex constants, * [What do I mean by "another" frustration? Let me talk to you some day about disallowing hex constants,
* or insisting that property names be quoted, or refusing to allow comments. I think it's fine for * or insisting that property names be quoted, or refusing to allow comments. I think it's fine for
* JSON.stringify() to produce output that adheres to rules like that -- although some parameters to control * JSON.stringify() to produce output that adheres to rules like that -- although some parameters to control
* the output would be nice -- but refusing to let JSON.parse() parse objects that are, in fact, perfectly * the output would be nice -- but it's completely unnecessary for JSON.parse() to refuse to parse objects
* parseable, is just JSON being a dick.] * that are perfectly valid.]
* *
* @this {Card} * @this {Card}
* @param {Array|undefined} data * @param {Array|undefined} data
@ -1971,14 +1981,14 @@ Card.prototype.initEGA = function(data, nMonitorType)
Card.prototype.saveCard = function() Card.prototype.saveCard = function()
{ {
var data = []; var data = [];
if (this.iCard !== undefined) { if (this.nCard !== undefined) {
data[0] = this.fActive; data[0] = this.fActive;
data[1] = this.regMode; data[1] = this.regMode;
data[2] = this.regColor; data[2] = this.regColor;
data[3] = this.regStatus; data[3] = this.regStatus;
data[4] = this.regCRTIndx | (this.regCRTPrev << 8); data[4] = this.regCRTIndx | (this.regCRTPrev << 8);
data[5] = this.regCRTData; data[5] = this.regCRTData;
if (this.iCard >= Video.CARD.EGA) { if (this.nCard >= Video.CARD.EGA) {
data[6] = this.saveEGA(); data[6] = this.saveEGA();
} }
data[7] = this.nInitCycles; data[7] = this.nInitCycles;
@ -2037,16 +2047,16 @@ Card.prototype.dumpCard = function()
*/ */
this.dumpRegs("CRTC", this.regCRTIndx, this.regCRTData, this.asCRTCRegs); this.dumpRegs("CRTC", this.regCRTIndx, this.regCRTData, this.asCRTCRegs);
if (this.iCard == Video.CARD.MDA || this.iCard == Video.CARD.CGA) { if (this.nCard == Video.CARD.MDA || this.nCard == Video.CARD.CGA) {
this.dumpRegs(" MODEREG", this.regMode); this.dumpRegs(" MODEREG", this.regMode);
this.dumpRegs(" STATUS1", this.regStatus); this.dumpRegs(" STATUS1", this.regStatus);
} }
if (this.iCard == Video.CARD.CGA) { if (this.nCard == Video.CARD.CGA) {
this.dumpRegs(" COLOR", this.regColor); this.dumpRegs(" COLOR", this.regColor);
} }
if (this.iCard >= Video.CARD.EGA) { if (this.nCard >= Video.CARD.EGA) {
this.dbg.println(" ATCDATA: " + this.fATCData); this.dbg.println(" ATCDATA: " + this.fATCData);
this.dumpRegs(" ATC", this.regATCIndx, this.regATCData, this.asATCRegs); this.dumpRegs(" ATC", this.regATCIndx, this.regATCData, this.asATCRegs);
this.dumpRegs(" GRC", this.regGRCIndx, this.regGRCData, this.asGRCRegs); this.dumpRegs(" GRC", this.regGRCIndx, this.regGRCData, this.asGRCRegs);
@ -3942,10 +3952,10 @@ Video.prototype.checkMode = function(fForce)
if (nMode == null) nMode = this.nModeDefault; if (nMode == null) nMode = this.nModeDefault;
} }
else { else {
if (card.iCard == Video.CARD.MDA) { if (card.nCard == Video.CARD.MDA) {
nMode = Video.MODE.MDA_80X25; nMode = Video.MODE.MDA_80X25;
} }
else if (card.iCard == Video.CARD.EGA) { else if (card.nCard == Video.CARD.EGA) {
/* /*
* The sizeBuffer we choose reflects the amount of physical address space that all 4 planes * The sizeBuffer we choose reflects the amount of physical address space that all 4 planes
* of EGA memory normally span, NOT the total amount of EGA memory. So for a 64Kb EGA card, * of EGA memory normally span, NOT the total amount of EGA memory. So for a 64Kb EGA card,