VGA scaffolding (piggy-backing on EGA)
This commit is contained in:
parent
9c10efe469
commit
f75acdf426
3 changed files with 181 additions and 149 deletions
|
|
@ -14,7 +14,7 @@
|
|||
<panel ref="/devices/pc/panel/btpanel.xml"/>
|
||||
<fdc ref="/disks/pc/library.xml" width="340px" automount='{A: {name: "PC-DOS 3.00 (Disk 1)", path: "/disks/pc/dos/ibm/3.00/PCDOS300-DISK1.json"}, B: {name: "PC-DOS 3.00 (Disk 2)", path: "/disks/pc/dos/ibm/3.00/PCDOS300-DISK2.json"}}'/>
|
||||
<hdcFoo id="hdcAT" type="at" drives='[{name:"20Mb Hard Disk",type:2}]'/>
|
||||
<chipset id="chipset" model="deskpro386" floppies="[1200,1200]"/>
|
||||
<chipset id="chipset" model="deskpro386" floppies="[1200,1200]" monitor="vga"/>
|
||||
<serial id="com1" adapter="1"/>
|
||||
<serial id="com2" adapter="2" binding="print"/>
|
||||
<mouse serial="com1"/>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ if (typeof module !== 'undefined') {
|
|||
* sound: true to enable (experimental) sound support (default); false to disable
|
||||
* scaleTimers: true to divide timer cycle counts by the CPU's cycle multiplier (default is false)
|
||||
* floppies: array of floppy drive sizes in Kb (default is "[360, 360]" if no sw1 value provided)
|
||||
* monitor: none|tv|color|mono (if no sw1 value provided, default is "ega" for 5170, "mono" otherwise)
|
||||
* monitor: none|tv|color|mono|ega|vga (if no sw1 value provided, default is "ega" for 5170, "mono" otherwise)
|
||||
* rtcDate: optional RTC date/time (in GMT) to use on reset; use the ISO 8601 format; eg: "2014-10-01T08:00:00"
|
||||
*
|
||||
* The conventions used for the sw1 and sw2 strings are that the left-most character represents DIP switch [1],
|
||||
|
|
@ -297,7 +297,8 @@ ChipSet.MONITOR = {
|
|||
COLOR: 2, // Color Display (5153)
|
||||
MONO: 3, // Monochrome Display (5151)
|
||||
EGACOLOR: 4, // Enhanced Color Display (5154) in High-Res Mode
|
||||
EGAEMULATION: 6 // Enhanced Color Display (5154) in Emulation Mode
|
||||
EGAEMULATION: 6, // Enhanced Color Display (5154) in Emulation Mode
|
||||
VGACOLOR: 7 // VGA Color Display
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -309,7 +310,8 @@ ChipSet.aMonitorSwitches = {
|
|||
"tv": 0x1,
|
||||
"color": 0x2,
|
||||
"mono": 0x3,
|
||||
"ega": 0x0
|
||||
"ega": 0x0,
|
||||
"vga": 0x0
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -101,24 +101,22 @@ function Video(parmsVideo, canvas, context, textarea, container)
|
|||
Component.call(this, "Video", parmsVideo, Video, Messages.VIDEO);
|
||||
|
||||
/*
|
||||
* This records the model specified (eg, "mda", "cga", "ega" or "" if none specified);
|
||||
* This records the model specified (eg, "mda", "cga", "ega", "vga" or "" if none specified);
|
||||
* when a model is specified, it overrides whatever model we infer from the ChipSet's switches
|
||||
* (since those motherboard switches tell us only the type of monitor, not the type of card).
|
||||
*/
|
||||
this.model = parmsVideo['model'];
|
||||
this.cbMemory = 0;
|
||||
this.nCard = Video.CARD.NAMES[this.model] || Video.CARD.MDA;
|
||||
|
||||
if (this.model == "ega") {
|
||||
this.sEGASW = parmsVideo['switches'];
|
||||
this.cbMemory = parmsVideo['memory'] || 0; // zero means fallback to the cardSpec's default size
|
||||
}
|
||||
this.cbMemory = parmsVideo['memory'] || 0; // zero means fallback to the cardSpec's default size
|
||||
this.sSwitches = parmsVideo['switches'];
|
||||
|
||||
/*
|
||||
* powerUp() uses the default mode ONLY if ChipSet doesn't give us a default.
|
||||
*/
|
||||
this.nModeDefault = parmsVideo['mode'];
|
||||
if (this.nModeDefault === undefined || Video.aModeParms[this.nModeDefault] === undefined) {
|
||||
this.nModeDefault = Video.MODES.MDA_80X25;
|
||||
this.nModeDefault = Video.MODE.MDA_80X25;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -336,12 +334,20 @@ Video.TRAPALL = true; // monitor all I/O by default (not just deltas)
|
|||
/*
|
||||
* Supported Cards
|
||||
*
|
||||
* Note that we choose IDs that match the default font ID for each card as well, just for consistency.
|
||||
* Note that we choose IDs that match the default font ID for each card as well, for convenience.
|
||||
*/
|
||||
Video.CARDS = {};
|
||||
Video.CARDS.MDA = 1;
|
||||
Video.CARDS.CGA = 3;
|
||||
Video.CARDS.EGA = 5;
|
||||
Video.CARD = {
|
||||
MDA: 1,
|
||||
CGA: 3,
|
||||
EGA: 5,
|
||||
VGA: 7,
|
||||
NAMES: {
|
||||
"mda": 1,
|
||||
"cga": 3,
|
||||
"ega": 5,
|
||||
"vga": 7
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Supported Monitors
|
||||
|
|
@ -448,7 +454,7 @@ Video.monitorSpecs[ChipSet.MONITOR.EGACOLOR] = {
|
|||
* 0x0: return SW4
|
||||
*
|
||||
* These 4 bits are also copied to the byte at 40:88h by the EGA BIOS, where bit 0 is SW1, bit 1 is SW2,
|
||||
* bit 2 is SW3 and bit 3 is SW4. Our switch settings come from bEGASW, which in turn comes from sEGASW,
|
||||
* bit 2 is SW3 and bit 3 is SW4. Our switch settings come from bEGASwitches, which in turn comes from sSwitches,
|
||||
* which in turn comes from the "switches" property passed to the Video component, if any.
|
||||
*
|
||||
* As usual, the switch settings are reversed in both direction and sense from the switch settings; the
|
||||
|
|
@ -462,7 +468,7 @@ Video.aEGAMonitorSwitches = {
|
|||
0x06: [ChipSet.MONITOR.TV, ChipSet.MONITOR.MONO, true], // "1001"
|
||||
0x07: [ChipSet.MONITOR.COLOR, ChipSet.MONITOR.MONO, true], // "0001"
|
||||
0x08: [ChipSet.MONITOR.EGAEMULATION, ChipSet.MONITOR.MONO, true], // "1110"
|
||||
0x09: [ChipSet.MONITOR.EGACOLOR, ChipSet.MONITOR.MONO, true], // "0110" [our default; see bEGASW below]
|
||||
0x09: [ChipSet.MONITOR.EGACOLOR, ChipSet.MONITOR.MONO, true], // "0110" [our default; see bEGASwitches below]
|
||||
0x0a: [ChipSet.MONITOR.MONO, ChipSet.MONITOR.TV, true], // "1010"
|
||||
0x0b: [ChipSet.MONITOR.MONO, ChipSet.MONITOR.COLOR, true], // "0010"
|
||||
0x00: [ChipSet.MONITOR.TV, ChipSet.MONITOR.MONO, false], // "1111"
|
||||
|
|
@ -490,20 +496,24 @@ Video.aEGAMonitorSwitches = {
|
|||
* situations as best they can (and when they don't, it should be considered a bug if some application is
|
||||
* broken as a result), but realistically, this is never going to be a 100% accurate hardware emulation.
|
||||
*/
|
||||
Video.MODES = {};
|
||||
Video.MODES.CGA_40X25_BW = 0;
|
||||
Video.MODES.CGA_40X25 = 1;
|
||||
Video.MODES.CGA_80X25_BW = 2;
|
||||
Video.MODES.CGA_80X25 = 3;
|
||||
Video.MODES.CGA_320X200 = 4;
|
||||
Video.MODES.CGA_320X200_BW = 5;
|
||||
Video.MODES.CGA_640X200 = 6;
|
||||
Video.MODES.MDA_80X25 = 7;
|
||||
Video.MODES.EGA_320X200 = 0x0D; // mapped at A000:0000
|
||||
Video.MODES.EGA_640X200 = 0x0E; // mapped at A000:0000
|
||||
Video.MODES.EGA_640X350_MONO = 0x0F; // mapped at A000:0000, monochrome
|
||||
Video.MODES.EGA_640X350 = 0x10; // mapped at A000:0000, color
|
||||
Video.MODES.UNKNOWN = 0xFF;
|
||||
Video.MODE = {
|
||||
CGA_40X25_BW: 0,
|
||||
CGA_40X25: 1,
|
||||
CGA_80X25_BW: 2,
|
||||
CGA_80X25: 3,
|
||||
CGA_320X200: 4,
|
||||
CGA_320X200_BW: 5,
|
||||
CGA_640X200: 6,
|
||||
MDA_80X25: 7,
|
||||
EGA_320X200: 0x0D, // mapped at A000:0000
|
||||
EGA_640X200: 0x0E, // mapped at A000:0000
|
||||
EGA_640X350_MONO: 0x0F, // mapped at A000:0000, monochrome
|
||||
EGA_640X350: 0x10, // mapped at A000:0000, color
|
||||
VGA_640X480_MONO: 0x11, // mapped at A000:0000, monochrome
|
||||
VGA_640X480: 0x12, // mapped at A000:0000, color
|
||||
VGA_320X200: 0x13, // mapped at A000:0000, color
|
||||
UNKNOWN: 0xFF
|
||||
};
|
||||
|
||||
/**
|
||||
* @class Font
|
||||
|
|
@ -535,13 +545,16 @@ Video.MODES.UNKNOWN = 0xFF;
|
|||
* dot patterns for 256 different characters. The character sets are identical to those provided by the
|
||||
* IBM Monochrome Display Adapter and the IBM Color/Graphics Monitor Adapter."
|
||||
*/
|
||||
Video.FONTS = {};
|
||||
Video.FONTS.MDA = 1; // 9x14 monochrome font
|
||||
Video.FONTS.MDAD = 2; // 18x28 monochrome font (this is the 9x14 font doubled)
|
||||
Video.FONTS.CGA = 3; // 8x8 color font
|
||||
Video.FONTS.CGAD = 6; // 16x16 color font (this is the 8x8 CGA font doubled)
|
||||
Video.FONTS.EGA = 5; // 9x14 color font
|
||||
Video.FONTS.EGAD = 10; // 18x28 color font (this is the 9x14 EGA font doubled)
|
||||
Video.FONT = {
|
||||
MDA: 1, // 9x14 monochrome font
|
||||
MDAD: 2, // 18x28 monochrome font (this is the 9x14 font doubled)
|
||||
CGA: 3, // 8x8 color font
|
||||
CGAD: 6, // 16x16 color font (this is the 8x8 CGA font doubled)
|
||||
EGA: 5, // 8x14 color font
|
||||
EGAD: 10, // 16x28 color font (this is the 8x14 EGA font doubled)
|
||||
VGA: 7, // 8x16 color font
|
||||
VGAD: 14 // 16x32 color font (this is the 8x16 VGA font doubled)
|
||||
};
|
||||
|
||||
/*
|
||||
* For each video mode, we need to know the following pieces of information:
|
||||
|
|
@ -563,19 +576,22 @@ Video.FONTS.EGAD = 10; // 18x28 color font (this is the 9x14 EGA font d
|
|||
* and it might not always be the best fit.
|
||||
*/
|
||||
Video.aModeParms = []; // Mode
|
||||
Video.aModeParms[Video.MODES.CGA_40X25] = [ 40, 25, 1, 0, Video.FONTS.CGA]; // 0x00
|
||||
Video.aModeParms[Video.MODES.CGA_80X25] = [ 80, 25, 1, 0, Video.FONTS.CGA]; // 0x02
|
||||
Video.aModeParms[Video.MODES.CGA_320X200] = [320, 200, 8, 192]; // 0x04
|
||||
Video.aModeParms[Video.MODES.CGA_640X200] = [640, 200, 16, 192]; // 0x06
|
||||
Video.aModeParms[Video.MODES.MDA_80X25] = [ 80, 25, 1, 0, Video.FONTS.MDA]; // 0x07
|
||||
Video.aModeParms[Video.MODES.EGA_320X200] = [320, 200, 16]; // 0x0D
|
||||
Video.aModeParms[Video.MODES.EGA_640X200] = [640, 200, 16]; // 0x0E
|
||||
Video.aModeParms[Video.MODES.EGA_640X350_MONO] = [640, 350, 16]; // 0x0F
|
||||
Video.aModeParms[Video.MODES.EGA_640X350] = [640, 350, 16]; // 0x10
|
||||
Video.aModeParms[Video.MODE.CGA_40X25] = [ 40, 25, 1, 0, Video.FONT.CGA]; // 0x00
|
||||
Video.aModeParms[Video.MODE.CGA_80X25] = [ 80, 25, 1, 0, Video.FONT.CGA]; // 0x02
|
||||
Video.aModeParms[Video.MODE.CGA_320X200] = [320, 200, 8, 192]; // 0x04
|
||||
Video.aModeParms[Video.MODE.CGA_640X200] = [640, 200, 16, 192]; // 0x06
|
||||
Video.aModeParms[Video.MODE.MDA_80X25] = [ 80, 25, 1, 0, Video.FONT.MDA]; // 0x07
|
||||
Video.aModeParms[Video.MODE.EGA_320X200] = [320, 200, 16]; // 0x0D
|
||||
Video.aModeParms[Video.MODE.EGA_640X200] = [640, 200, 16]; // 0x0E
|
||||
Video.aModeParms[Video.MODE.EGA_640X350_MONO] = [640, 350, 16]; // 0x0F
|
||||
Video.aModeParms[Video.MODE.EGA_640X350] = [640, 350, 16]; // 0x10
|
||||
Video.aModeParms[Video.MODE.VGA_640X480_MONO] = [640, 480, 16]; // 0x11
|
||||
Video.aModeParms[Video.MODE.VGA_640X480] = [640, 480, 16]; // 0x12
|
||||
Video.aModeParms[Video.MODE.VGA_320X200] = [320, 200, 16]; // 0x13
|
||||
|
||||
Video.aModeParms[Video.MODES.CGA_40X25_BW] = Video.aModeParms[Video.MODES.CGA_40X25]; // 0x01
|
||||
Video.aModeParms[Video.MODES.CGA_80X25_BW] = Video.aModeParms[Video.MODES.CGA_80X25]; // 0x03
|
||||
Video.aModeParms[Video.MODES.CGA_320X200_BW] = Video.aModeParms[Video.MODES.CGA_320X200]; // 0x05
|
||||
Video.aModeParms[Video.MODE.CGA_40X25_BW] = Video.aModeParms[Video.MODE.CGA_40X25]; // 0x01
|
||||
Video.aModeParms[Video.MODE.CGA_80X25_BW] = Video.aModeParms[Video.MODE.CGA_80X25]; // 0x03
|
||||
Video.aModeParms[Video.MODE.CGA_320X200_BW] = Video.aModeParms[Video.MODE.CGA_320X200]; // 0x05
|
||||
|
||||
/*
|
||||
* MDA attribute byte definitions
|
||||
|
|
@ -746,7 +762,7 @@ Video.aEGADWToByte[0x80808080|0] = 0xf;
|
|||
*
|
||||
* @constructor
|
||||
* @param {Video} [video]
|
||||
* @param {number} [iCard] (see Video.CARDS.*)
|
||||
* @param {number} [iCard] (see Video.CARD.*)
|
||||
* @param {Array|null} [data]
|
||||
* @param {number} [cbMemory] is specified if the card must allocate its own memory buffer
|
||||
*/
|
||||
|
|
@ -806,7 +822,7 @@ function Card(video, iCard, data, cbMemory)
|
|||
this.nCRTCRegs = Card.CRTC.TOTAL_REGS;
|
||||
this.asCRTCRegs = DEBUGGER? Card.CRTC.REGS : [];
|
||||
|
||||
if (iCard == Video.CARDS.EGA) {
|
||||
if (iCard >= Video.CARD.EGA) {
|
||||
this.nCRTCRegs = Card.CRTC.EGA.TOTAL_REGS;
|
||||
this.asCRTCRegs = DEBUGGER? Card.CRTC.EGA_REGS : [];
|
||||
this.initEGA(data[6], nMonitorType);
|
||||
|
|
@ -1055,9 +1071,10 @@ Card.FEAT_CTRL.BITS = 0x03; // feature control bits
|
|||
|
||||
Card.STATUS0 = {};
|
||||
Card.STATUS0.PORT = 0x3C2; // read-only (aka STATUS0, to distinguish it from PORT_CGA_STATUS)
|
||||
Card.STATUS0.RESERVED = 0x0F;
|
||||
Card.STATUS0.SWSENSE = 0x10;
|
||||
Card.STATUS0.SWSENSE_SHIFT = 4;
|
||||
Card.STATUS0.FEAT = 0x60;
|
||||
Card.STATUS0.FEAT = 0x60; // VGA: reserved
|
||||
Card.STATUS0.INTERRUPT = 0x80; // 1: video is being displayed; 0: vertical retrace is occurring
|
||||
|
||||
/*
|
||||
|
|
@ -1707,7 +1724,7 @@ Card.prototype.saveCard = function()
|
|||
data[3] = this.statusReg;
|
||||
data[4] = this.iCRTCReg | (this.iCRTCPrev << 8);
|
||||
data[5] = this.aCRTCRegs;
|
||||
if (this.iCard == Video.CARDS.EGA) {
|
||||
if (this.iCard >= Video.CARD.EGA) {
|
||||
data[6] = this.saveEGA();
|
||||
}
|
||||
data[7] = this.nInitCycles;
|
||||
|
|
@ -1765,16 +1782,16 @@ Card.prototype.dumpCard = function()
|
|||
*/
|
||||
this.dumpRegs("CRTC", this.iCRTCReg, this.aCRTCRegs, this.asCRTCRegs);
|
||||
|
||||
if (this.iCard == Video.CARDS.MDA || this.iCard == Video.CARDS.CGA) {
|
||||
if (this.iCard == Video.CARD.MDA || this.iCard == Video.CARD.CGA) {
|
||||
this.dumpRegs(" MODEREG", this.modeReg);
|
||||
this.dumpRegs(" STATUS1", this.statusReg);
|
||||
}
|
||||
|
||||
if (this.iCard == Video.CARDS.CGA) {
|
||||
if (this.iCard == Video.CARD.CGA) {
|
||||
this.dumpRegs(" COLOR", this.colorReg);
|
||||
}
|
||||
|
||||
if (this.iCard == Video.CARDS.EGA) {
|
||||
if (this.iCard >= Video.CARD.EGA) {
|
||||
this.dbg.println(" ATCDATA: " + this.fATCData);
|
||||
this.dumpRegs(" ATC", this.iATCReg, this.aATCRegs, this.asATCRegs);
|
||||
this.dumpRegs(" GRC", this.iGRCReg, this.aGRCRegs, this.asGRCRegs);
|
||||
|
|
@ -1947,9 +1964,10 @@ Card.prototype.setMemoryAccess = function(nAccess)
|
|||
* to access the buffer directly, instead of going through the Bus memory interface.
|
||||
*/
|
||||
Video.cardSpecs = [];
|
||||
Video.cardSpecs[Video.CARDS.MDA] = ["MDA", Card.MDA.CRTC.INDX.PORT, 0xB0000, 0x01000, 0, ChipSet.MONITOR.MONO];
|
||||
Video.cardSpecs[Video.CARDS.CGA] = ["CGA", Card.CGA.CRTC.INDX.PORT, 0xB8000, 0x04000, 0, ChipSet.MONITOR.COLOR];
|
||||
Video.cardSpecs[Video.CARDS.EGA] = ["EGA", Card.CGA.CRTC.INDX.PORT, 0xB8000, 0x04000, 0x10000, ChipSet.MONITOR.EGACOLOR];
|
||||
Video.cardSpecs[Video.CARD.MDA] = ["MDA", Card.MDA.CRTC.INDX.PORT, 0xB0000, 0x01000, 0, ChipSet.MONITOR.MONO];
|
||||
Video.cardSpecs[Video.CARD.CGA] = ["CGA", Card.CGA.CRTC.INDX.PORT, 0xB8000, 0x04000, 0, ChipSet.MONITOR.COLOR];
|
||||
Video.cardSpecs[Video.CARD.EGA] = ["EGA", Card.CGA.CRTC.INDX.PORT, 0xB8000, 0x04000, 0x10000, ChipSet.MONITOR.EGACOLOR];
|
||||
Video.cardSpecs[Video.CARD.VGA] = ["VGA", Card.CGA.CRTC.INDX.PORT, 0xB8000, 0x04000, 0x10000, ChipSet.MONITOR.VGACOLOR];
|
||||
|
||||
/**
|
||||
* initBus(cmp, bus, cpu, dbg)
|
||||
|
|
@ -1972,7 +1990,7 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
bus.addPortInputTable(this, Video.aPortInput);
|
||||
bus.addPortOutputTable(this, Video.aPortOutput);
|
||||
|
||||
if (this.model == "ega") {
|
||||
if (this.nCard >= Video.CARD.EGA) {
|
||||
bus.addPortInputTable(this, Video.aEGAPortInput);
|
||||
bus.addPortOutputTable(this, Video.aEGAPortOutput);
|
||||
}
|
||||
|
|
@ -1996,10 +2014,10 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
this.kbd.setBinding(this.textareaScreen? "textarea" : "canvas", "kbd", this.inputScreen);
|
||||
}
|
||||
|
||||
this.bEGASW = 0x09; // our default "switches" setting (see aEGAMonitorSwitches)
|
||||
this.bEGASwitches = 0x09; // our default "switches" setting (see aEGAMonitorSwitches)
|
||||
this.chipset = cmp.getComponentByType("ChipSet");
|
||||
if (this.chipset && this.sEGASW) {
|
||||
this.bEGASW = this.chipset.parseSwitches(this.sEGASW, this.bEGASW);
|
||||
if (this.chipset && this.sSwitches) {
|
||||
if (this.nCard == Video.CARD.EGA) this.bEGASwitches = this.chipset.parseSwitches(this.sSwitches, this.bEGASwitches);
|
||||
}
|
||||
|
||||
if (this.kbd && this.fTouchScreen) this.captureTouch();
|
||||
|
|
@ -2444,28 +2462,27 @@ Video.prototype.reset = function()
|
|||
nMonitorType = this.chipset.getSWVideoMonitor();
|
||||
}
|
||||
|
||||
var fEGA = false;
|
||||
if (this.model) {
|
||||
switch (this.model) {
|
||||
case "ega":
|
||||
fEGA = true;
|
||||
var aMonitors = Video.aEGAMonitorSwitches[this.bEGASW];
|
||||
/*
|
||||
* TODO: Figure out how to deal with aMonitors[2], the boolean which indicates
|
||||
* whether the EGA is driving the primary monitor (true) or the secondary monitor (false).
|
||||
*/
|
||||
if (aMonitors) nMonitorType = aMonitors[0];
|
||||
if (!nMonitorType) nMonitorType = ChipSet.MONITOR.EGACOLOR;
|
||||
break;
|
||||
case "mda":
|
||||
nMonitorType = ChipSet.MONITOR.MONO;
|
||||
break;
|
||||
case "cga":
|
||||
/* falls through */
|
||||
default:
|
||||
nMonitorType = ChipSet.MONITOR.COLOR;
|
||||
break;
|
||||
}
|
||||
switch (this.nCard) {
|
||||
case Video.CARD.VGA:
|
||||
nMonitorType = ChipSet.MONITOR.VGACOLOR;
|
||||
break;
|
||||
case Video.CARD.EGA:
|
||||
var aMonitors = Video.aEGAMonitorSwitches[this.bEGASwitches];
|
||||
/*
|
||||
* TODO: Figure out how to deal with aMonitors[2], the boolean which indicates
|
||||
* whether the EGA is driving the primary monitor (true) or the secondary monitor (false).
|
||||
*/
|
||||
if (aMonitors) nMonitorType = aMonitors[0];
|
||||
if (!nMonitorType) nMonitorType = ChipSet.MONITOR.EGACOLOR;
|
||||
break;
|
||||
case Video.CARD.MDA:
|
||||
nMonitorType = ChipSet.MONITOR.MONO;
|
||||
break;
|
||||
case Video.CARD.CGA:
|
||||
/* falls through */
|
||||
default:
|
||||
nMonitorType = ChipSet.MONITOR.COLOR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.nMonitorType !== nMonitorType) {
|
||||
|
|
@ -2474,16 +2491,14 @@ Video.prototype.reset = function()
|
|||
}
|
||||
|
||||
this.cardActive = null;
|
||||
this.cardMono = this.cardMDA = new Card(this, Video.CARDS.MDA);
|
||||
this.cardColor = this.cardCGA = new Card(this, Video.CARDS.CGA);
|
||||
this.cardMono = this.cardMDA = new Card(this, Video.CARD.MDA);
|
||||
this.cardColor = this.cardCGA = new Card(this, Video.CARD.CGA);
|
||||
|
||||
if (!fEGA) {
|
||||
/*
|
||||
* Define a dummy (uninitialized) EGA card for now
|
||||
*/
|
||||
this.cardEGA = new Card();
|
||||
} else {
|
||||
this.cardEGA = new Card(this, Video.CARDS.EGA, null, this.cbMemory);
|
||||
if (this.nCard < Video.CARD.EGA) {
|
||||
this.cardEGA = new Card(); // define a dummy (uninitialized) EGA card for now
|
||||
}
|
||||
else {
|
||||
this.cardEGA = new Card(this, this.nCard, null, this.cbMemory);
|
||||
this.enableEGA();
|
||||
}
|
||||
|
||||
|
|
@ -2493,7 +2508,7 @@ Video.prototype.reset = function()
|
|||
this.buildFonts();
|
||||
|
||||
this.nMode = null;
|
||||
this.nModeDefault = (nMonitorType == ChipSet.MONITOR.MONO? Video.MODES.MDA_80X25 : Video.MODES.CGA_80X25);
|
||||
this.nModeDefault = (nMonitorType == ChipSet.MONITOR.MONO? Video.MODE.MDA_80X25 : Video.MODE.CGA_80X25);
|
||||
|
||||
this.iCellCursor = -1; // initially, there is no visible cursor cell
|
||||
this.cBlinks = -1; // initially, blinking is not active
|
||||
|
|
@ -2524,7 +2539,7 @@ Video.prototype.reset = function()
|
|||
for (var addrScreen = this.cardActive.addrBuffer; addrScreen < addrScreenLimit; addrScreen += 2) {
|
||||
var dataRandom = Math.floor(Math.random() * 0x10000);
|
||||
var bChar, bAttr;
|
||||
if (this.nMonitorType == ChipSet.MONITOR.EGACOLOR) {
|
||||
if (this.nMonitorType == ChipSet.MONITOR.EGACOLOR || this.nMonitorType == ChipSet.MONITOR.VGACOLOR) {
|
||||
/*
|
||||
* For the EGA, we choose sequential characters; for random characters, copy the MDA/CGA code below.
|
||||
*/
|
||||
|
|
@ -2596,13 +2611,13 @@ Video.prototype.restore = function(data)
|
|||
this.nMode = a[2];
|
||||
|
||||
this.cardActive = null;
|
||||
this.cardMono = this.cardMDA = new Card(this, Video.CARDS.MDA, data[0]);
|
||||
this.cardColor = this.cardCGA = new Card(this, Video.CARDS.CGA, data[1]);
|
||||
this.cardMono = this.cardMDA = new Card(this, Video.CARD.MDA, data[0]);
|
||||
this.cardColor = this.cardCGA = new Card(this, Video.CARD.CGA, data[1]);
|
||||
|
||||
/*
|
||||
* If no EGA was originally initialized, then cardEGA will remain uninitialized.
|
||||
*/
|
||||
this.cardEGA = new Card(this, Video.CARDS.EGA, data[3], this.cbMemory);
|
||||
this.cardEGA = new Card(this, this.nCard, data[3], this.cbMemory);
|
||||
if (this.cardEGA.fActive) this.enableEGA();
|
||||
|
||||
/*
|
||||
|
|
@ -2747,10 +2762,10 @@ Video.prototype.onLoadSetFonts = function(sFontFile, sFontData, nErrorCode)
|
|||
*
|
||||
* Called by copyROM() whenever a ROM with a 'notify' attribute set to our component ID has been loaded.
|
||||
*
|
||||
* If model is "ega", then we assume the associated ROM is the original IBM EGA ROM, which stores
|
||||
* its 8x14 font data at 0x2230 (and unlike the MDA/CGA character generator ROM, which splits the first
|
||||
* 8 rows and remaining 6 rows of each character across separate 2K chunks, the bytes for all the EGA
|
||||
* character rows are contiguous); the total size of the 8x14 font is 0xE00 bytes.
|
||||
* For IBM EGA cards, we assume the associated ROM is the original IBM EGA ROM, which stores its 8x14 font
|
||||
* data at 0x2230 (and unlike the MDA/CGA character generator ROM, which splits the first 8 rows and
|
||||
* remaining 6 rows of each character across separate 2K chunks, the bytes for all the EGA character rows
|
||||
* are contiguous); the total size of the 8x14 font is 0xE00 bytes.
|
||||
*
|
||||
* At 0x3030, there is an "ALPHA SUPPLEMENT" table, which contains 15 bytes per row instead of 14,
|
||||
* because each row is preceded by one byte containing the corresponding ASCII code; there are 20 entries
|
||||
|
|
@ -2765,12 +2780,18 @@ Video.prototype.onLoadSetFonts = function(sFontFile, sFontData, nErrorCode)
|
|||
* font generation to support it (as opposed to "init-time" generation, which is all we do now). There's
|
||||
* probably a similar need for user-defined fonts; for now, they're just not supported.
|
||||
*
|
||||
* IBM VGA NOTES: The IBM VGA "ALPHA SUPPLEMENT" table appears at the same delta (+0x0E00) as the IBM EGA
|
||||
* table (ie, 0x3f8d + 0x0e00 = 0x4d8d). If we assume the same length for the supplement table (20 chars,
|
||||
* 15 bytes per char, for a total of 0x12c bytes, rounded up to 0x130), that would put the 8x8 data at
|
||||
* offset 0x4ebd. I suspect the data ends at around 0x5eb9, meaning it's organized as 16 bytes per char
|
||||
* instead of 8.
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {Array.<number>} abROM
|
||||
*/
|
||||
Video.prototype.onROMLoad = function(abROM)
|
||||
{
|
||||
if (this.model == "ega") {
|
||||
if (this.nCard == Video.CARD.EGA) {
|
||||
/*
|
||||
* TODO: Unlike the MDA/CGA font data, we may want to hang onto this data, so that we can
|
||||
* regenerate the color font(s) whenever the foreground and/or background colors have changed.
|
||||
|
|
@ -2778,6 +2799,10 @@ Video.prototype.onROMLoad = function(abROM)
|
|||
if (DEBUG) this.printMessage("onROMLoad(): EGA fonts loaded");
|
||||
this.setFontData(abROM, [0x2230, 0x3160], 8);
|
||||
}
|
||||
else if (this.nCard == Video.CARD.VGA) {
|
||||
if (DEBUG) this.printMessage("onROMLoad(): VGA fonts loaded");
|
||||
this.setFontData(abROM, [0x3f8d, 0x0000], 8);
|
||||
}
|
||||
this.setReady();
|
||||
};
|
||||
|
||||
|
|
@ -2909,27 +2934,26 @@ Video.prototype.buildFonts = function()
|
|||
var fChanges = false;
|
||||
|
||||
/*
|
||||
* There's no point building any fonts if (a) we're in a non-windowed (eg, command-line) environment or
|
||||
* (b) no font data was loaded.
|
||||
* There's no point building any fonts if we're in a non-windowed (eg, command-line) environment or no font data was loaded.
|
||||
*/
|
||||
if (window && this.abFontData) {
|
||||
|
||||
var offSplit = this.cxFontChar? 0 : 0x0800;
|
||||
var cxChar = this.cxFontChar? this.cxFontChar : 9;
|
||||
|
||||
if (this.buildFont(Video.FONTS.MDA, this.aFontOffsets[0], offSplit, cxChar, 14, this.abFontData, Video.aMDAColors, Video.aMDAColorMap)) {
|
||||
if (this.buildFont(Video.FONT.MDA, this.aFontOffsets[0], offSplit, cxChar, 14, this.abFontData, Video.aMDAColors, Video.aMDAColorMap)) {
|
||||
fChanges = true;
|
||||
}
|
||||
|
||||
var aRGBColors = this.getCardColors();
|
||||
offSplit = 0x0000;
|
||||
cxChar = this.cxFontChar? this.cxFontChar : 8;
|
||||
if (this.buildFont(Video.FONTS.CGA, this.aFontOffsets[1], offSplit, cxChar, 8, this.abFontData, aRGBColors)) {
|
||||
if (this.buildFont(Video.FONT.CGA, this.aFontOffsets[1], offSplit, cxChar, 8, this.abFontData, aRGBColors)) {
|
||||
fChanges = true;
|
||||
}
|
||||
|
||||
if (this.cxFontChar) {
|
||||
if (this.buildFont(Video.FONTS.EGA, this.aFontOffsets[0], 0, this.cxFontChar, 14, this.abFontData, aRGBColors)) {
|
||||
if (this.buildFont(this.nCard, this.aFontOffsets[0], 0, this.cxFontChar, 14, this.abFontData, aRGBColors)) {
|
||||
fChanges = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -2944,7 +2968,7 @@ Video.prototype.buildFonts = function()
|
|||
*
|
||||
* @this {Video}
|
||||
* @param {number} nFont
|
||||
* @param {number} offData is the offset of the font data
|
||||
* @param {number} offData is the offset of the font data, zero if none
|
||||
* @param {number} offSplit is the offset of any split font data, or zero if not split
|
||||
* @param {number} cxChar is the width of the font characters
|
||||
* @param {number} cyChar is the height of the font characters
|
||||
|
|
@ -2957,22 +2981,23 @@ Video.prototype.buildFont = function(nFont, offData, offSplit, cxChar, cyChar, a
|
|||
{
|
||||
var fChanges = false;
|
||||
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("buildFont(" + nFont + "): building " + Video.cardSpecs[nFont][0] + " font");
|
||||
}
|
||||
if (this.createFont(nFont, offData, offSplit, cxChar, cyChar, abFontData, aRGBColors, aColorMap)) fChanges = true;
|
||||
|
||||
/*
|
||||
* If font-doubling is enabled, then load a double-size version of the font as well, as it provides
|
||||
* sharper rendering, especially when the screen cell size is a multiple of the above font cell size;
|
||||
* in the case of the CGA, this may also be useful for 40-column modes.
|
||||
*/
|
||||
if (this.fDoubleFont) {
|
||||
nFont <<= 1;
|
||||
if (offData) {
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("buildFont(" + nFont + "): building " + Video.cardSpecs[nFont >> 1][0] + " double-size font");
|
||||
this.printMessage("buildFont(" + nFont + "): building " + Video.cardSpecs[nFont][0] + " font");
|
||||
}
|
||||
if (this.createFont(nFont, offData, offSplit, cxChar, cyChar, abFontData, aRGBColors, aColorMap)) fChanges = true;
|
||||
/*
|
||||
* If font-doubling is enabled, then load a double-size version of the font as well, as it provides
|
||||
* sharper rendering, especially when the screen cell size is a multiple of the above font cell size;
|
||||
* in the case of the CGA, this may also be useful for 40-column modes.
|
||||
*/
|
||||
if (this.fDoubleFont) {
|
||||
nFont <<= 1;
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("buildFont(" + nFont + "): building " + Video.cardSpecs[nFont >> 1][0] + " double-size font");
|
||||
}
|
||||
if (this.createFont(nFont, offData, offSplit, cxChar, cyChar, abFontData, aRGBColors, aColorMap)) fChanges = true;
|
||||
}
|
||||
}
|
||||
return fChanges;
|
||||
};
|
||||
|
|
@ -3226,9 +3251,9 @@ Video.prototype.checkCursor = function()
|
|||
* HACK: The original EGA BIOS has a cursor emulation bug when 43-line mode is enabled, so we attempt to detect
|
||||
* that particular combination of bad values and automatically fix them.
|
||||
*/
|
||||
var fEGA = false;
|
||||
var fEGAHack = false;
|
||||
if (this.cardActive === this.cardEGA) {
|
||||
fEGA = true;
|
||||
fEGAHack = true;
|
||||
if (bCursorMax == 7 && bCursorStart == 4 && !bCursorEnd) bCursorEnd = 7;
|
||||
}
|
||||
|
||||
|
|
@ -3240,7 +3265,7 @@ Video.prototype.checkCursor = function()
|
|||
* TODO: Verify whether the second test (bCursorStart > bCursorMax) should also result in a hidden cursor;
|
||||
* ThinkTank sets both start and end values to 0x0f, which doesn't make sense on a CGA, where the max is 0x07.
|
||||
*/
|
||||
if ((bCursorFlags & Card.CRTC.CURSOR_START.BLINKOFF) || bCursorStart > bCursorEnd && !fEGA || bCursorStart > bCursorMax) {
|
||||
if ((bCursorFlags & Card.CRTC.CURSOR_START.BLINKOFF) || bCursorStart > bCursorEnd && !fEGAHack || bCursorStart > bCursorMax) {
|
||||
this.removeCursor();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -3427,17 +3452,19 @@ Video.prototype.setDimensions = function()
|
|||
this.nFont = 0;
|
||||
this.nCols = this.nDefaultCols;
|
||||
this.nRows = this.nDefaultRows;
|
||||
this.nCellsPerWord = Video.aModeParms[Video.MODES.MDA_80X25][2];
|
||||
this.nCellsPerWord = Video.aModeParms[Video.MODE.MDA_80X25][2];
|
||||
|
||||
var cbPadding = 0;
|
||||
var modeParms = Video.aModeParms[this.nMode];
|
||||
if (modeParms) {
|
||||
|
||||
this.nCols = modeParms[0];
|
||||
this.nRows = modeParms[1];
|
||||
this.nCellsPerWord = modeParms[2];
|
||||
cbPadding = modeParms[3] || 0;
|
||||
this.nFont = modeParms[4]; // this will be undefined for graphics modes
|
||||
if (this.nMonitorType == ChipSet.MONITOR.EGACOLOR) {
|
||||
|
||||
if (this.nMonitorType == ChipSet.MONITOR.EGACOLOR || this.nMonitorType == ChipSet.MONITOR.VGACOLOR) {
|
||||
/*
|
||||
* When an EGA is connected to a CGA monitor, the old aModeParms table is correct: we must
|
||||
* use the hard-coded 8x8 "CGA_80" font. But when it's connected to an EGA monitor, we want
|
||||
|
|
@ -3446,7 +3473,7 @@ Video.prototype.setDimensions = function()
|
|||
* TODO: Can an EGA with a monochrome monitor be programmed for 43-line mode as well? If so,
|
||||
* then we'll need to load another MDA font variation, because we only load an 9x14 font for MDA.
|
||||
*/
|
||||
if (this.cardActive === this.cardEGA && this.nFont == Video.FONTS.CGA) {
|
||||
if (this.cardActive === this.cardEGA && this.nFont == Video.FONT.CGA) {
|
||||
if (this.cardEGA.aCRTCRegs[Card.CRTC.MAX_SCAN_LINE] == 7) {
|
||||
/*
|
||||
* Vertical resolution of 350 divided by 8 (ie, scan lines 0-7) yields 43 whole rows.
|
||||
|
|
@ -3460,8 +3487,11 @@ Video.prototype.setDimensions = function()
|
|||
else /* if (this.cardEGA.aCRTCRegs[Card.CRTC.MAX_SCAN_LINE] == 13) */ {
|
||||
/*
|
||||
* Vertical resolution of 350 divided by 14 (ie, scan lines 0-13) yields exactly 25 rows.
|
||||
*
|
||||
* Note that a card's default font matches its card ID (eg, Video.CARD.EGA == Video.FONT.EGA,
|
||||
* and Video.CARD.VGA == Video.FONT.VGA)
|
||||
*/
|
||||
this.nFont = Video.FONTS.EGA;
|
||||
this.nFont = this.nCard;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3471,7 +3501,7 @@ Video.prototype.setDimensions = function()
|
|||
this.nCellCache = (this.nCells / this.nCellsPerWord);
|
||||
this.cbScreen = (this.nCellCache << 1) + cbPadding;
|
||||
this.cbSplit = (cbPadding? ((this.cbScreen + cbPadding) >> 1) : 0);
|
||||
if (this.nMode >= Video.MODES.EGA_320X200) this.nCellCache <<= 1;
|
||||
if (this.nMode >= Video.MODE.EGA_320X200) this.nCellCache <<= 1;
|
||||
|
||||
/*
|
||||
* If no fonts were successfully loaded, there's no point in initializing the remaining drawing parameters.
|
||||
|
|
@ -3617,10 +3647,10 @@ Video.prototype.checkMode = function(fForce)
|
|||
if (nMode == null) nMode = this.nModeDefault;
|
||||
}
|
||||
else {
|
||||
if (card.iCard == Video.CARDS.MDA) {
|
||||
nMode = Video.MODES.MDA_80X25;
|
||||
if (card.iCard == Video.CARD.MDA) {
|
||||
nMode = Video.MODE.MDA_80X25;
|
||||
}
|
||||
else if (card.iCard == Video.CARDS.EGA) {
|
||||
else if (card.iCard == Video.CARD.EGA) {
|
||||
/*
|
||||
* 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,
|
||||
|
|
@ -3640,22 +3670,22 @@ Video.prototype.checkMode = function(fForce)
|
|||
case Card.GRC.MISC.MAPA0128:
|
||||
card.addrBuffer = 0xA0000;
|
||||
card.sizeBuffer = cbBuffer; // 0x20000
|
||||
nMode = Video.MODES.UNKNOWN; // no BIOS mode uses this mapping, but we don't want to leave nMode null if we've come this far
|
||||
nMode = Video.MODE.UNKNOWN; // no BIOS mode uses this mapping, but we don't want to leave nMode null if we've come this far
|
||||
break;
|
||||
case Card.GRC.MISC.MAPA064:
|
||||
card.addrBuffer = 0xA0000;
|
||||
card.sizeBuffer = cbBuffer; // 0x10000
|
||||
nMode = (this.nMonitorType == ChipSet.MONITOR.MONO? Video.MODES.EGA_640X350_MONO : Video.MODES.EGA_640X350);
|
||||
nMode = (this.nMonitorType == ChipSet.MONITOR.MONO? Video.MODE.EGA_640X350_MONO : Video.MODE.EGA_640X350);
|
||||
break;
|
||||
case Card.GRC.MISC.MAPB032:
|
||||
card.addrBuffer = 0xB0000;
|
||||
card.sizeBuffer = cbBufferText;
|
||||
nMode = Video.MODES.MDA_80X25;
|
||||
nMode = Video.MODE.MDA_80X25;
|
||||
break;
|
||||
case Card.GRC.MISC.MAPB832:
|
||||
card.addrBuffer = 0xB8000;
|
||||
card.sizeBuffer = cbBufferText;
|
||||
nMode = (this.nMonitorType == ChipSet.MONITOR.MONO? Video.MODES.CGA_80X25_BW : Video.MODES.CGA_80X25);
|
||||
nMode = (this.nMonitorType == ChipSet.MONITOR.MONO? Video.MODE.CGA_80X25_BW : Video.MODE.CGA_80X25);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -3664,7 +3694,7 @@ Video.prototype.checkMode = function(fForce)
|
|||
var fSEQDotClock = (card.aSEQRegs[Card.SEQ.CLK.INDX] & Card.SEQ.CLK.DOTCLOCK);
|
||||
var nCRTCVertTotal = card.aCRTCRegs[Card.CRTC.EGA.VERT_TOTAL] | ((card.aCRTCRegs[Card.CRTC.EGA.OVERFLOW.INDX] & Card.CRTC.EGA.OVERFLOW.VERT_TOTAL) << 8);
|
||||
|
||||
if (nMode != Video.MODES.UNKNOWN) {
|
||||
if (nMode != Video.MODE.UNKNOWN) {
|
||||
if (!(regGRCMisc & Card.GRC.MISC.GRAPHICS)) {
|
||||
if (fSEQDotClock) nMode -= 2;
|
||||
} else {
|
||||
|
|
@ -3673,14 +3703,14 @@ Video.prototype.checkMode = function(fForce)
|
|||
// Since nMode will have been assigned a default of either 0x02 or 0x03, convert that to either
|
||||
// 0x05 or 0x04 if we're in a low-res graphics mode, 0x06 otherwise.
|
||||
//
|
||||
nMode = fSEQDotClock? (7 - nMode) : Video.MODES.CGA_640X200;
|
||||
nMode = fSEQDotClock? (7 - nMode) : Video.MODE.CGA_640X200;
|
||||
} else {
|
||||
//
|
||||
// card.addrBuffer must be 0xA0000, so we need to discriminate between modes 0x0D through 0x10;
|
||||
// we've already defaulted to 0x0F or 0x10, so determine if it's 0x0D or 0x0E (ie, a 200-row mode)
|
||||
// and then which one (ie, 320 wide or 640 wide).
|
||||
//
|
||||
if (nCRTCVertTotal < 350) nMode = (fSEQDotClock? Video.MODES.EGA_320X200 : Video.MODES.EGA_640X200);
|
||||
if (nCRTCVertTotal < 350) nMode = (fSEQDotClock? Video.MODE.EGA_320X200 : Video.MODE.EGA_640X200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3695,10 +3725,10 @@ Video.prototype.checkMode = function(fForce)
|
|||
* off, using a hard-coded mode value (0x25) that does NOT necessarily match the the CGA video mode currently in effect.
|
||||
*/
|
||||
if (!(card.modeReg & Card.CGA.MODE.GRAPHIC_SEL)) {
|
||||
nMode = ((card.modeReg & Card.CGA.MODE._80X25)? Video.MODES.CGA_80X25 : Video.MODES.CGA_40X25);
|
||||
nMode = ((card.modeReg & Card.CGA.MODE._80X25)? Video.MODE.CGA_80X25 : Video.MODE.CGA_40X25);
|
||||
if (card.modeReg & Card.CGA.MODE.BW_SEL) nMode -= 1;
|
||||
} else {
|
||||
nMode = ((card.modeReg & Card.CGA.MODE.HIRES_BW)? Video.MODES.CGA_640X200 : Video.MODES.CGA_320X200_BW);
|
||||
nMode = ((card.modeReg & Card.CGA.MODE.HIRES_BW)? Video.MODE.CGA_640X200 : Video.MODE.CGA_320X200_BW);
|
||||
if (!(card.modeReg & Card.CGA.MODE.BW_SEL)) nMode -= 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -3755,7 +3785,7 @@ Video.prototype.setMode = function(nMode, fForce)
|
|||
* (MDA or CGA) don't allocate/manage their own memory buffer, but even then, it's still a good idea
|
||||
* to always force this operation (eg, in case a switch setting changed the active video card).
|
||||
*/
|
||||
var card = this.cardActive || (nMode == Video.MODES.MDA_80X25? this.cardMono : this.cardColor);
|
||||
var card = this.cardActive || (nMode == Video.MODE.MDA_80X25? this.cardMono : this.cardColor);
|
||||
|
||||
if (card != this.cardActive || card.addrBuffer != this.addrBuffer || card.sizeBuffer != this.sizeBuffer) {
|
||||
|
||||
|
|
@ -4527,7 +4557,7 @@ Video.prototype.outATC = function(port, bOut, addrFrom)
|
|||
Video.prototype.inStatus0 = function(port, addrFrom)
|
||||
{
|
||||
var iBit = 3 - ((this.cardEGA.miscReg & Card.MISC.CLK_SELECT) >> 2); // this is the desired SW # (0-3)
|
||||
var bSWBit = (this.bEGASW & (1 << iBit)) << (Card.STATUS0.SWSENSE_SHIFT - iBit);
|
||||
var bSWBit = (this.bEGASwitches & (1 << iBit)) << (Card.STATUS0.SWSENSE_SHIFT - iBit);
|
||||
var b = ((this.cardEGA.status0 & ~Card.STATUS0.SWSENSE) | bSWBit);
|
||||
/*
|
||||
* TODO: Figure out where Card.STATUS0.FEAT bits should come from....
|
||||
|
|
|
|||
Loading…
Reference in a new issue