Added 'diagnostics' (0, 1, or 2) and 'randomize' (0 or 1) PCx86 machine parameters to control diagnostic message display/prompting and video screen randomization, respectively
This commit is contained in:
parent
7f973a03b9
commit
aac9a13328
7 changed files with 1072 additions and 1023 deletions
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -117,6 +117,8 @@ class Computer extends Component {
|
|||
*
|
||||
* url: the location of the machine XML file
|
||||
*
|
||||
* diagnostics: 0 for none, 1 for normal diagnostics, and 2 for diagnostics with prompting
|
||||
*
|
||||
* If a predefined state is supplied AND it's successfully loaded, then resume behavior
|
||||
* defaults to '1' (ie, resume enabled without prompting).
|
||||
*
|
||||
|
|
@ -147,6 +149,8 @@ class Computer extends Component {
|
|||
this.setMachineParms(parmsMachine);
|
||||
|
||||
this.fAutoPower = this.getMachineParm('autoPower', parmsComputer);
|
||||
this.nDiagnostics = +this.getMachineParm('diagnostics', parmsComputer);
|
||||
if (!(this.nDiagnostics >= 0 && this.nDiagnostics <= 2)) this.nDiagnostics = 1;
|
||||
|
||||
/*
|
||||
* nPowerChange is 0 while the power state is stable, 1 while power is transitioning
|
||||
|
|
@ -218,6 +222,7 @@ class Computer extends Component {
|
|||
this.printComputer = this.panel.print;
|
||||
this.printlnComputer = this.panel.println;
|
||||
}
|
||||
|
||||
for (iComponent = 0; iComponent < aComponents.length; iComponent++) {
|
||||
component = aComponents[iComponent];
|
||||
component.notice = function noticeComputer(s, fPrintOnly, id) {
|
||||
|
|
@ -232,8 +237,11 @@ class Computer extends Component {
|
|||
return cmp.printlnComputer.call(this, s, type, id);
|
||||
}.bind(component);
|
||||
}
|
||||
|
||||
this.cDiagnosticScreens = 0;
|
||||
if (!this.controlPanel) this.enableDiagnostics();
|
||||
if (!this.controlPanel && this.nDiagnostics) {
|
||||
this.enableDiagnostics();
|
||||
}
|
||||
|
||||
this.println(PCX86.APPNAME + " v" + (XMLVERSION || PCX86.APPVERSION) + "\n" + COPYRIGHT + "\n" + LICENSE);
|
||||
|
||||
|
|
@ -351,19 +359,21 @@ class Computer extends Component {
|
|||
*/
|
||||
enableDiagnostics()
|
||||
{
|
||||
for (var i = 0; i < this.aVideo.length; i++) {
|
||||
var video = this.aVideo[i];
|
||||
if (video) {
|
||||
var control = video.getTextArea();
|
||||
if (control) {
|
||||
/*
|
||||
* By default, the Video textarea overlay has opacity and lineHeight styles set to "0"
|
||||
* to make the overall textarea and its blinking caret invisible (respectively), so in order
|
||||
* to use it as a diagnostic display, we must temporarily set both those styles to "1".
|
||||
*/
|
||||
control.style.opacity = "1";
|
||||
control.style.lineHeight = "1";
|
||||
this.cDiagnosticScreens++;
|
||||
if (!this.cDiagnosticScreens) {
|
||||
for (var i = 0; i < this.aVideo.length; i++) {
|
||||
var video = this.aVideo[i];
|
||||
if (video) {
|
||||
var control = video.getTextArea();
|
||||
if (control) {
|
||||
/*
|
||||
* By default, the Video textarea overlay has opacity and lineHeight styles set to "0"
|
||||
* to make the overall textarea and its blinking caret invisible (respectively), so in order
|
||||
* to use it as a diagnostic display, we must temporarily set both those styles to "1".
|
||||
*/
|
||||
control.style.opacity = "1";
|
||||
control.style.lineHeight = "1";
|
||||
this.cDiagnosticScreens++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -373,33 +383,43 @@ class Computer extends Component {
|
|||
* disableDiagnostics()
|
||||
*
|
||||
* @this {Computer}
|
||||
* @return {boolean} (true if diagnostics were, or already are, disabled; false if they remain disabled)
|
||||
*/
|
||||
disableDiagnostics()
|
||||
{
|
||||
for (var i = 0; i < this.aVideo.length; i++) {
|
||||
var video = this.aVideo[i];
|
||||
if (video) {
|
||||
var control = video.getTextArea();
|
||||
if (control) {
|
||||
var agent = Web.getUserAgent();
|
||||
/*
|
||||
* Return the Video textarea overlay's opacity and lineHeight styles to their original values.
|
||||
*/
|
||||
control.style.opacity = "0";
|
||||
control.style.lineHeight = "0";
|
||||
/*
|
||||
* Setting lineHeight in IE isn't sufficient to hide the caret; we must also set fontSize to "0",
|
||||
* and we make the change IE-specific because it can have weird side-effects in other browsers (eg,
|
||||
* it makes Safari on iOS over-zoom whenever the textarea receives focus). And making it IE-specific
|
||||
* is, as usual, harder than it should be, because IE11 stopped identifying itself as "MSIE", hence
|
||||
* the additional "Trident" check.
|
||||
*/
|
||||
if (agent.indexOf("MSIE") >= 0 || agent.indexOf("Trident") >= 0) control.style.fontSize = "0";
|
||||
control.value = "";
|
||||
if (this.cDiagnosticScreens) {
|
||||
if (this.nDiagnostics == 2) {
|
||||
this.nDiagnostics++;
|
||||
this.println("Press any key to continue...");
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < this.aVideo.length; i++) {
|
||||
var video = this.aVideo[i];
|
||||
if (video) {
|
||||
var control = video.getTextArea();
|
||||
if (control) {
|
||||
var agent = Web.getUserAgent();
|
||||
/*
|
||||
* Return the Video textarea overlay's opacity and lineHeight styles to their original values.
|
||||
*/
|
||||
control.style.opacity = "0";
|
||||
control.style.lineHeight = "0";
|
||||
/*
|
||||
* Setting lineHeight in IE isn't sufficient to hide the caret; we must also set fontSize to "0",
|
||||
* and we make the change IE-specific because it can have weird side-effects in other browsers (eg,
|
||||
* it makes Safari on iOS over-zoom whenever the textarea receives focus). And making it IE-specific
|
||||
* is, as usual, harder than it should be, because IE11 stopped identifying itself as "MSIE", hence
|
||||
* the additional "Trident" check.
|
||||
*/
|
||||
if (agent.indexOf("MSIE") >= 0 || agent.indexOf("Trident") >= 0) control.style.fontSize = "0";
|
||||
control.value = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
this.cDiagnosticScreens = 0;
|
||||
}
|
||||
this.cDiagnosticScreens = 0;
|
||||
this.nDiagnostics = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -411,22 +431,39 @@ class Computer extends Component {
|
|||
*/
|
||||
outputDiagnostics(sMessage, sType)
|
||||
{
|
||||
if (!this.cDiagnosticScreens) return;
|
||||
for (var i = 0; i < this.aVideo.length; i++) {
|
||||
var video = this.aVideo[i];
|
||||
if (video) {
|
||||
var control = video.getTextArea();
|
||||
if (control) {
|
||||
if (sType != Component.TYPE.PROGRESS || sMessage.slice(-3) != "...") {
|
||||
Component.appendControl(control, sMessage + '\n');
|
||||
} else {
|
||||
Component.replaceControl(control, sMessage, sMessage + '.');
|
||||
if (this.cDiagnosticScreens) {
|
||||
for (var i = 0; i < this.aVideo.length; i++) {
|
||||
var video = this.aVideo[i];
|
||||
if (video) {
|
||||
var control = video.getTextArea();
|
||||
if (control) {
|
||||
if (sType != Component.TYPE.PROGRESS || sMessage.slice(-3) != "...") {
|
||||
Component.appendControl(control, sMessage + '\n');
|
||||
} else {
|
||||
Component.replaceControl(control, sMessage, sMessage + '.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* notifyKbdEvent(event)
|
||||
*
|
||||
* This is called by the Keyboard component for all key presses, and it is effectively a no-op except
|
||||
* in the one special case where disableDiagnostics() has delayed powerOn until a key is pressed.
|
||||
*
|
||||
* @this {Computer}
|
||||
*/
|
||||
notifyKbdEvent(event)
|
||||
{
|
||||
if (this.nDiagnostics == 3) {
|
||||
this.nDiagnostics++;
|
||||
this.setReady();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* getMachineID()
|
||||
*
|
||||
|
|
@ -859,23 +896,28 @@ class Computer extends Component {
|
|||
*/
|
||||
donePowerOn(aParms)
|
||||
{
|
||||
var stateComputer = aParms[0];
|
||||
var fRepower = (aParms[1] < 0);
|
||||
var fRestore = aParms[2];
|
||||
if (!this.flags.initDone) {
|
||||
if (!this.disableDiagnostics()) {
|
||||
this.setReady(false);
|
||||
this.wait(this.donePowerOn, aParms);
|
||||
return;
|
||||
}
|
||||
this.flags.initDone = true;
|
||||
}
|
||||
|
||||
if (DEBUG && this.flags.powered && this.messageEnabled()) {
|
||||
this.printMessage("Computer.donePowerOn(): redundant");
|
||||
}
|
||||
|
||||
if (!this.flags.initDone) {
|
||||
this.disableDiagnostics();
|
||||
this.flags.initDone = true;
|
||||
}
|
||||
var stateComputer = aParms[0];
|
||||
var fRepower = (aParms[1] < 0);
|
||||
var fRestore = aParms[2];
|
||||
|
||||
this.flags.powered = true;
|
||||
var controlPower = this.bindings["power"];
|
||||
if (controlPower) controlPower.textContent = "Shutdown";
|
||||
|
||||
this.flags.powered = true;
|
||||
|
||||
/*
|
||||
* Once we get to this point, we're guaranteed that all components are ready, so it's safe to power the CPU;
|
||||
* the CPU should begin executing immediately, unless a debugger is attached.
|
||||
|
|
|
|||
|
|
@ -571,7 +571,9 @@ class CPU extends Component {
|
|||
calcCycles()
|
||||
{
|
||||
var nMultiplier = this.counts.mhzCurrent / this.counts.mhzBase;
|
||||
if (!nMultiplier || nMultiplier > this.counts.nTargetMultiplier) nMultiplier = this.counts.nTargetMultiplier;
|
||||
if (!nMultiplier || nMultiplier > this.counts.nTargetMultiplier) {
|
||||
nMultiplier = this.counts.nTargetMultiplier;
|
||||
}
|
||||
this.counts.msPerYield = Math.round(1000 / CPU.YIELDS_PER_SECOND);
|
||||
this.counts.nCyclesPerYield = Math.floor(this.counts.nBaseCyclesPerSecond / CPU.YIELDS_PER_SECOND * nMultiplier);
|
||||
this.counts.nCurrentMultiplier = nMultiplier;
|
||||
|
|
|
|||
|
|
@ -1647,6 +1647,8 @@ class Keyboard extends Component {
|
|||
|
||||
this.sInjectBuffer = ""; // actual key events should stop any injection currently in progress
|
||||
|
||||
this.cmp.notifyKbdEvent(event);
|
||||
|
||||
if (this.fAllDown) {
|
||||
var simCode = this.checkActiveKey();
|
||||
if (simCode && this.isAlphaKey(simCode) && this.isAlphaKey(keyCode) && simCode != keyCode) {
|
||||
|
|
|
|||
|
|
@ -83,11 +83,11 @@ class Mouse extends Component {
|
|||
this.setActive(false);
|
||||
this.fCaptured = this.fLocked = false;
|
||||
/*
|
||||
* Initially, no video devices, and therefore no input devices, are attached. initBus() will update aVideo,
|
||||
* and powerUp() will update aInput.
|
||||
* Initially, no video devices, and therefore no screens, are attached. initBus() will update aVideo,
|
||||
* and powerUp() will update aScreens.
|
||||
*/
|
||||
this.aVideo = [];
|
||||
this.aInput = [];
|
||||
this.aScreens = [];
|
||||
this.setReady();
|
||||
}
|
||||
|
||||
|
|
@ -183,10 +183,10 @@ class Mouse extends Component {
|
|||
}
|
||||
}
|
||||
if (this.componentAdapter) {
|
||||
this.aInput = []; // ensure the input device array is empty before (re)filling it
|
||||
this.aScreens = []; // ensure the screen array is empty before (re)filling it
|
||||
for (var i = 0; i < this.aVideo.length; i++) {
|
||||
var input = this.aVideo[i].getInput(this);
|
||||
if (input) this.aInput.push(input);
|
||||
var screen = this.aVideo[i].getScreen(this);
|
||||
if (screen) this.aScreens.push(screen);
|
||||
}
|
||||
} else {
|
||||
Component.warning(this.id + ": " + this.sAdapterType + " " + this.idAdapter + " unavailable");
|
||||
|
|
@ -322,8 +322,8 @@ class Mouse extends Component {
|
|||
captureAll()
|
||||
{
|
||||
if (!this.fCaptured) {
|
||||
for (var i = 0; i < this.aInput.length; i++) {
|
||||
if (this.captureMouse(this.aInput[i])) this.fCaptured = true;
|
||||
for (var i = 0; i < this.aScreens.length; i++) {
|
||||
if (this.captureMouse(this.aScreens[i])) this.fCaptured = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -336,8 +336,8 @@ class Mouse extends Component {
|
|||
releaseAll()
|
||||
{
|
||||
if (this.fCaptured) {
|
||||
for (var i = 0; i < this.aInput.length; i++) {
|
||||
if (this.releaseMouse(this.aInput[i])) this.fCaptured = false;
|
||||
for (var i = 0; i < this.aScreens.length; i++) {
|
||||
if (this.releaseMouse(this.aScreens[i])) this.fCaptured = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -425,7 +425,7 @@ class Mouse extends Component {
|
|||
if (fDown !== undefined) {
|
||||
if (this.fLocked === false) {
|
||||
/*
|
||||
* If there's no support for automatic pointer locking in the Video component, then notifyPointerActive()
|
||||
* If there's no support for automatic pointer locking in the Video component, notifyPointerActive()
|
||||
* will return false, and we will set fLocked to null, ensuring that we never attempt this again.
|
||||
*/
|
||||
if (!this.aVideo.length || !this.aVideo[0].notifyPointerActive(true)) {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ if (NODE) {
|
|||
|
||||
/*
|
||||
* MDA/CGA Support
|
||||
* ---------------
|
||||
*
|
||||
* Since there's a lot of similarity between the MDA and CGA (eg, their text-mode video buffer
|
||||
* format, and their use of the 6845 CRT controller), since the MDA ROM contains the fonts used
|
||||
|
|
@ -81,10 +82,9 @@ if (NODE) {
|
|||
* TODO: Whenever there are borders, they should be filled with the CGA's overscan colors. However,
|
||||
* in the case of graphics modes (and text modes whenever font scaling is enabled), we don't reserve
|
||||
* any space for borders, so if borders are important, explicit border support will be required.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* EGA Support
|
||||
* -----------
|
||||
*
|
||||
* EGA support piggy-backs on the existing MDA/CGA support. All the existing MDA/CGA port handlers
|
||||
* now refer to either cardMono or cardColor (instead of directly to cardMDA or cardCGA), enabling
|
||||
|
|
@ -103,10 +103,9 @@ if (NODE) {
|
|||
* control certain assumptions about the virtual display's capabilities (ie, Color Display vs. Enhanced
|
||||
* Color Display). P3 can switch all the I/O ports from 0x3nn to 0x2nn; the default is 0x3nn, and
|
||||
* that's the only port range the EGA ROM supports as well.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* VGA Support
|
||||
* -----------
|
||||
*
|
||||
* More will be said here about PCjs VGA support later. But first, a word from IBM: "Video Graphics Array [VGA]
|
||||
* Programming Considerations":
|
||||
|
|
@ -2166,6 +2165,7 @@ class Video extends Component {
|
|||
* fontROM: path to .rom file (or a JSON representation) containing the character set
|
||||
* touchScreen: string specifying desired touch-screen support (default is none)
|
||||
* autoLock: true to (attempt to) auto-lock the mouse to the canvas (default is false)
|
||||
* randomize: 1 enables screen randomization, 0 disables (default is 1)
|
||||
*
|
||||
* An EGA/VGA may specify the following additional properties:
|
||||
*
|
||||
|
|
@ -2220,6 +2220,8 @@ class Video extends Component {
|
|||
this.nCard = aModelDefaults[0];
|
||||
this.cbMemory = parmsVideo['memory'] || 0; // zero means fallback to the cardSpec's default size
|
||||
this.sSwitches = parmsVideo['switches'];
|
||||
this.nRandomize = parmsVideo['randomize'];
|
||||
if (this.nRandomize == null) this.nRandomize = 1;
|
||||
|
||||
/*
|
||||
* powerUp() uses the default mode ONLY if ChipSet doesn't give us a default.
|
||||
|
|
@ -2418,6 +2420,9 @@ class Video extends Component {
|
|||
this.cpu = cpu;
|
||||
this.dbg = dbg;
|
||||
|
||||
var nRandomize = +cmp.getMachineParm('randomize');
|
||||
if (nRandomize >= 0 && nRandomize <= 1) this.nRandomize = nRandomize;
|
||||
|
||||
/*
|
||||
* nCard will be undefined if no model was explicitly set (whereas this.nCard is ALWAYS defined).
|
||||
*/
|
||||
|
|
@ -2588,15 +2593,15 @@ class Video extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* getInput()
|
||||
* getScreen()
|
||||
*
|
||||
* This is an interface used by the Mouse component, so that it can invoke capture/release mouse events from the screen element.
|
||||
* This is an interface used by the Mouse component, so that it can capture mouse events from the screen.
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {Mouse} [mouse]
|
||||
* @return {Object|undefined}
|
||||
*/
|
||||
getInput(mouse)
|
||||
getScreen(mouse)
|
||||
{
|
||||
this.mouse = mouse;
|
||||
return this.inputScreen;
|
||||
|
|
@ -3127,7 +3132,6 @@ class Video extends Component {
|
|||
*/
|
||||
reset()
|
||||
{
|
||||
var fRandomize = true;
|
||||
var nMonitorType = ChipSet.MONITOR.NONE;
|
||||
|
||||
/*
|
||||
|
|
@ -3176,7 +3180,6 @@ class Video extends Component {
|
|||
|
||||
if (this.nMonitorType !== nMonitorType) {
|
||||
this.nMonitorType = nMonitorType;
|
||||
fRandomize = true;
|
||||
}
|
||||
|
||||
this.cardActive = null;
|
||||
|
|
@ -3199,7 +3202,7 @@ class Video extends Component {
|
|||
this.nMode = null;
|
||||
this.setMode(this.nModeDefault);
|
||||
|
||||
if (this.cardActive.addrBuffer && fRandomize) {
|
||||
if (this.cardActive.addrBuffer && this.nRandomize) {
|
||||
/*
|
||||
* On the initial power-on, we initialize the video buffer to random characters, as a way of testing
|
||||
* whether our font(s) were successfully loaded. It's assumed that our default display mode is a text mode,
|
||||
|
|
|
|||
Loading…
Reference in a new issue