Merge branch 'master' into gh-pages

This commit is contained in:
Jeff Parsons 2017-07-20 20:02:16 -07:00
commit 3398a9fdd1
18 changed files with 3019 additions and 2919 deletions

View file

@ -8,7 +8,7 @@ redirect_from:
---
IBM PC Machine Configurations
---
-----------------------------
PCjs supports these early [IBM PC Machines](#ibm-pc-machines):

View file

@ -2,6 +2,19 @@
<fdc id="fdcNEC" pos="left" padLeft="8px" padBottom="8px">
<control type="list" binding="listDrives"/>
<control type="list" binding="listDisks">
<disk path="/disks/pcx86/dos/ibm/0.90/PCDOS090.json">PC-DOS 0.90</disk>
<disk path="/disks/pcx86/dos/ibm/1.00/PCDOS100.json">PC-DOS 1.00</disk>
<disk path="/disks/pcx86/dos/ibm/1.10/PCDOS110.json">PC-DOS 1.10</disk>
<disk path="/disks/pcx86/dos/ibm/2.00/PCDOS200-DISK1.json">PC-DOS 2.00 (Disk 1)</disk>
<disk path="/disks/pcx86/dos/ibm/2.00/PCDOS200-DISK2.json">PC-DOS 2.00 (Disk 2)</disk>
<disk path="/disks/pcx86/dos/ibm/2.10/PCDOS210-DISK1.json">PC-DOS 2.10 (Disk 1)</disk>
<disk path="/disks/pcx86/dos/ibm/2.10/PCDOS210-DISK2.json">PC-DOS 2.10 (Disk 2)</disk>
<disk path="/disks/pcx86/dos/ibm/3.00/PCDOS300-DISK1.json">PC-DOS 3.00 (Disk 1)</disk>
<disk path="/disks/pcx86/dos/ibm/3.00/PCDOS300-DISK2.json">PC-DOS 3.00 (Disk 2)</disk>
<disk path="/disks/pcx86/dos/ibm/3.10/PCDOS310-DISK1.json">PC-DOS 3.10 (Disk 1)</disk>
<disk path="/disks/pcx86/dos/ibm/3.10/PCDOS310-DISK2.json">PC-DOS 3.10 (Disk 2)</disk>
<disk path="/disks/pcx86/dos/ibm/3.20/PCDOS320-DISK1.json">PC-DOS 3.20 (Disk 1)</disk>
<disk path="/disks/pcx86/dos/ibm/3.20/PCDOS320-DISK2.json">PC-DOS 3.20 (Disk 2)</disk>
<disk path="/disks/pcx86/dos/microsoft/3.20/MSDOS320-DISK1.json">MS-DOS 3.20 (Disk 1)</disk>
<disk path="/disks/pcx86/dos/microsoft/3.20/MSDOS320-DISK2.json">MS-DOS 3.20 (Disk 2)</disk>
<disk path="/disks/pcx86/dos/microsoft/3.20/MSDOS320-DISK3-PROGREF1.json">MS-DOS 3.20 (ProgRef 1)</disk>

View file

@ -13,8 +13,8 @@ PC-SIG Library 8th Edition CD-ROM (April 1990)
The machine below has access to all 2,121 diskette images from the PC-SIG Library 8th Edition CD-ROM (April 1990).
The directory listings were generated from the folder's [manifest](manifest.xml) using
[disklist](/modules/diskdump/bin/disklist), a custom PCjs JavaScript utility. The same machine is also available
[with the PCjs Debugger](debugger/).
<a href="/modules/diskdump/bin/disklist" download="disklist.js">disklist</a>, a custom PCjs JavaScript utility.
The same machine is also available [with the PCjs Debugger](debugger/).
{% include machine.html id="pcsig08" %}

View file

@ -2,6 +2,14 @@
<fdc id="fdcNEC" pos="left" padLeft="8px" padBottom="8px">
<control type="list" binding="listDrives"/>
<control type="list" binding="listDisks">
<manifest ref="/disks/pcx86/dos/ibm/0.90/manifest.xml"/>
<manifest ref="/disks/pcx86/dos/ibm/1.00/manifest.xml"/>
<manifest ref="/disks/pcx86/dos/ibm/1.10/manifest.xml"/>
<manifest ref="/disks/pcx86/dos/ibm/2.00/manifest.xml"/>
<manifest ref="/disks/pcx86/dos/ibm/2.10/manifest.xml"/>
<manifest ref="/disks/pcx86/dos/ibm/3.00/manifest.xml"/>
<manifest ref="/disks/pcx86/dos/ibm/3.10/manifest.xml"/>
<manifest ref="/disks/pcx86/dos/ibm/3.20/manifest.xml"/>
<manifest ref="/disks/pcx86/dos/microsoft/3.20/manifest.xml"/>
<manifest ref="/disks/pcx86/shareware/pcsig08/manifest.xml"/>
</control>

View file

@ -2,6 +2,8 @@
layout: page
title: Microsoft Windows 95 (First Retail Release)
permalink: /disks/pcx86/windows/win95/4.00.950/
redirect_from:
- /disks/pc/windows/win95/4.00.950/
machines:
- id: deskpro386
type: pcx86

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -5,10 +5,11 @@ permalink: /modules/pcx86/
---
IBM PC Emulation Module (PCx86)
===
===============================
Overview
---
--------
PCx86 is the IBM PC emulation module powering all our [IBM PC Machines](/devices/pcx86/machine/).
This module divides PC functionality into variety of logical and visual components.
@ -84,7 +85,7 @@ referencing other components. Device components should define an initBus() noti
*Computer* component will call after it has created/initialized the *Bus* component.
Features
---
--------
[List of major existing features goes here]

View file

@ -5,7 +5,7 @@ permalink: /modules/pcx86/bin/
---
Running PCx86 From The Command-Line
---
-----------------------------------
In this *bin* directory, run:
@ -26,15 +26,19 @@ The following output should appear:
PCx86 v1.x.x
Copyright © 2012-2017 Jeff Parsons <Jeff@pcjs.org>
License: GPL version 3 or later <http://gnu.org/licenses/gpl.html>
warning: Machine component type 'HDC' not found
warning: Machine component type 'Mouse' not found
ibm5150.pc-mda-64k object created
PCx86> bus: 8Kb ROM at 000FE000
bus: 32Kb ROM at 000F6000
bus: 576Kb RAM at 00000000
bus: 4Kb VIDEO at 000B0000
PCx86> Bus: 8Kb ROM at 000FE000
Bus: 32Kb ROM at 000F6000
notice: Mounted diskette "PC-DOS 2.00 (Disk 1)" in drive A
notice: Mounted diskette "PC-DOS 2.00 (Disk 2)" in drive B
Bus: 576Kb RAM at 0000
Bus: 4Kb VIDEO at 000B0000
Type ? for help with PCx86 Debugger commands
AX=0000 BX=0000 CX=0000 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
SS=0000 DS=0000 ES=0000 PS=F002 V0 D0 I0 T0 S0 Z0 A0 P0 C0
&FFFF:0000 EA5BE000F0 JMP &F000:E05B (romBIOS+0x0000005B)
&FFFF:0000 EA5BE000F0 JMP &F000:E05B (romBIOS+0x005B)
Start the machine with a `g` command:

View file

@ -893,6 +893,28 @@ class Computer extends Component {
*/
checkPower()
{
if (this.flags.unloading) {
/*
* We happen to know that we're currently only called by the CPU's onClickRun() function, so
* if the unloading flag is set, then we've somehow gotten into a weird state where the machine
* thinks it's being (or has been) unloaded by the browser, but in fact, it has not.
*
* The only time I've seen this happen is when the user clicks a link on a page that the browser
* decided to treat as a download operation, instead of loading a new page. The proper way to
* resolve that confusion is to set the "download" attribute on the link (which will prevent the
* page's "onbeforeunload" handler from being called in the first place), but we cannot guarantee
* that all such links will have their "download" attribute properly set.
*
* Hence, this code: we do the same thing that the show() function does, which is to attempt a
* REPOWER operation. If that doesn't result in the powered flag getting turned back on, well,
* then we're probably screwed.
*/
this.flags.unloading = false;
if (this.flags.initDone && !this.flags.powered) {
this.powerOn(Computer.RESUME_REPOWER);
}
}
if (this.flags.powered) return true;
var component = null, iComponent;
@ -1703,6 +1725,9 @@ class Computer extends Component {
var computer = /** @type {Computer} */ (Component.getComponentByType("Computer", parmsComputer['id']));
if (computer) {
/*
* Clear new flag that Component functions (eg, notice()) should check before alerting the user.
*/
computer.flags.unloading = false;
if (DEBUG && computer.messageEnabled()) {
@ -1710,7 +1735,7 @@ class Computer extends Component {
}
if (computer.flags.initDone && !computer.flags.powered) {
/**
/*
* Repower the computer, notifying every component to continue running as-is.
*/
computer.powerOn(Computer.RESUME_REPOWER);
@ -1755,7 +1780,7 @@ class Computer extends Component {
if (computer) {
/*
* Added a new flag that Component functions (eg, notice()) should check before alerting the user.
* Set new flag that Component functions (eg, notice()) should check before alerting the user.
*/
computer.flags.unloading = true;

View file

@ -472,11 +472,20 @@ class CPU extends Component {
case "run":
this.bindings[sBinding] = control;
control.onclick = function onClickRun() {
var fRunning = cpu.flags.running;
if (!cpu.cmp || !cpu.cmp.checkPower()) return;
if (!cpu.flags.running)
cpu.runCPU(true);
else
cpu.stopCPU(true);
/*
* We snapped the CPU's running flag before calling checkPower() because there are rare (REPOWER)
* situations where checkPower() will have started the CPU as well. So toggle the CPU state ONLY
* if the running flag remains unchanged.
*/
if (fRunning == cpu.flags.running) {
if (!cpu.flags.running) {
cpu.runCPU(true);
} else {
cpu.stopCPU(true);
}
}
};
fBound = true;
break;

View file

@ -2353,10 +2353,10 @@ class Video extends Component {
* is exasperating; browsers can't agree on 'full' or 'Full, 'request' or 'Request', 'screen' or 'Screen', and
* while some browsers honor other browser prefixes, most browsers don't.
*/
this.doFullScreen = null;
if ((this.container = container)) {
this.doFullScreen = container['requestFullscreen'] || container['msRequestFullscreen'] || container['mozRequestFullScreen'] || container['webkitRequestFullscreen'];
if (this.doFullScreen) {
this.container = container;
if (this.container) {
this.container.doFullScreen = container['requestFullscreen'] || container['msRequestFullscreen'] || container['mozRequestFullScreen'] || container['webkitRequestFullscreen'];
if (this.container.doFullScreen) {
for (i = 0; i < asWebPrefixes.length; i++) {
sEvent = asWebPrefixes[i] + 'fullscreenchange';
if ('on' + sEvent in document) {
@ -2572,7 +2572,7 @@ class Video extends Component {
switch (sBinding) {
case "fullScreen":
if (this.doFullScreen) {
if (this.container && this.container.doFullScreen) {
control.onclick = function onClickFullScreen() {
if (DEBUG) video.printMessage("fullScreen()");
video.goFullScreen();
@ -2658,7 +2658,7 @@ class Video extends Component {
{
var fSuccess = false;
if (this.container) {
if (this.doFullScreen) {
if (this.container.doFullScreen) {
/*
* Styling the container with a width of "100%" and a height of "auto" works great when the aspect ratio
* of our virtual screen is at least roughly equivalent to the physical screen's aspect ratio, but now that
@ -2709,7 +2709,7 @@ class Video extends Component {
this.canvasScreen.style.margin = "auto";
}
this.container.style.backgroundColor = this.colorScreen;
this.doFullScreen();
this.container.doFullScreen();
fSuccess = true;
}
this.setFocus();

View file

@ -3777,140 +3777,141 @@ class X86CPU extends CPU {
popWord()
{
var w = this.getWord(this.regLSP);
this.regLSP = (this.regLSP + (I386? this.sizeData : 2))|0;
/*
* Properly comparing regLSP to regLSPLimit would normally require coercing both to unsigned
* (ie, floating-point) values. But instead, we do a subtraction, (regLSPLimit - regLSP), and
* if the result is negative, we need only be concerned if the signs of both numbers are the same
* (ie, the sign of their XOR'ed union is positive).
*
* TODO: I'm combining the old 8088 address-wrap check with the new segment-limit check,
* even though the correct time to do the latter is immediately BEFORE the fetch, not AFTER;
* I'm working around this for now by applying a -1 fudge factor to the fault check below.
* Comparing regLSP to regLSPLimit requires coercing both to unsigned (ie, floating-point) values.
* If we didn't, when we subtracted a 32-bit value like 0x1 from a 32-bit limit like 0xFFFFFFF0 (-16),
* we would have a negative result, even though the value was well below the limit.
*/
var off = ((this.regLSPLimit - this.regLSP)|0);
if (off < 0 && (this.regLSPLimit ^ this.regLSP) >= 0) {
var delta = (this.regLSPLimit >>> 0) - (this.regLSP >>> 0);
if (delta < 0) {
/*
* There's no such thing as an SS fault on the 8086/8088, and I'm assuming that, on newer
* processors, when the stack segment limit is set to the maximum, it's OK for the stack to wrap.
* There's no such thing as an SS fault on the 8086/8088, and in fact, we have to support the
* operation even when the address straddles the wrap boundary; other emulators tend to barf on
* a wrap, usually because they're running in V86 mode instead of real mode.
*/
if (this.model <= X86.MODEL_8088 || !this.segSS.fExpDown && this.segSS.limit == this.segSS.maskAddr || this.segSS.fExpDown && !this.segSS.limit) {
if (this.model <= X86.MODEL_8088) {
this.setSP((this.regLSP - this.segSS.base) & this.segSS.maskAddr);
} else if (off < -1) { // fudge factor
X86.helpFault.call(this, X86.EXCEPTION.SS_FAULT, 0);
if (delta < -1) {
w = (w & 0xff) | (this.getByte(this.regLSP - 1) << 8);
}
}
else {
/*
* I'm assuming that, on newer processors, when the stack segment limit is set to the maximum,
* it's OK for the stack to wrap, unless the new address is straddling the wrap boundary (ie, when
* delta is < 0 and > -sizeData).
*/
if (!this.segSS.fExpDown && this.segSS.limit == this.segSS.maskAddr || this.segSS.fExpDown && !this.segSS.limit) {
this.setSP((this.regLSP - this.segSS.base) & this.segSS.maskAddr);
} else {
/*
* TODO: I'm combining the old 8088 address-wrap check with the new segment-limit check, even though the
* correct time to do the latter is immediately BEFORE the fetch, not AFTER; I'm working around this for now
* by applying a -1 fudge factor to the following fault check.
*/
if (delta < -1) {
X86.helpFault.call(this, X86.EXCEPTION.SS_FAULT, 0);
}
}
}
}
return w;
}
/**
* pushData(d, width, size)
*
* This function serves two very limited purposes: 1) the ability to push data according to a previous
* operand size (width), and 2) the ability to write fewer bytes than the width if necessary (size).
*
* The former occurs when a 32-bit code segment performs a 16:32 call to a 16-bit code segment; after the
* new 16-bit code segment is loaded (and possible stack switch occurs), the return address (both segment
* and offset) must still be pushed as 32-bit values.
*
* The latter occurs with segment register pushes. When a 32-bit operand size is in effect (ie, width is 4),
* only the low 16 bits should be written (size must be 2). For all other kinds of pushes, width and size are
* impliedly the same.
*
* @this {X86CPU}
* @param {number} d is the data to push at current SP; SP decreased by size
* @param {number} width is the width of the data to push, in bytes (must be either 2 or 4)
* @param {number} size is the size of the data to push, in bytes (must be 1, 2, or 4, and <= width)
*/
pushData(d, width, size)
{
this.assert((width == 2 || width == 4) && (size > 0 && size <= width));
var regLSP = (this.regLSP - width)|0;
/*
* Properly comparing regLSP to regLSPLimitLow would normally require coercing both to unsigned
* (ie, floating-point) values. But instead, we do a subtraction, (regLSP - regLSPLimitLow), and
* if the result is negative, we need only be concerned if the signs of both numbers are the same
* (ie, the sign of their XOR'ed union is positive).
*/
if (((regLSP - this.regLSPLimitLow)|0) < 0 && (this.regLSPLimitLow ^ regLSP) >= 0) {
/*
* There's no such thing as an SS fault on the 8086/8088, and I'm assuming that, on newer
* processors, when the stack segment limit is set to the maximum, it's OK for the stack to wrap.
*/
if (this.model <= X86.MODEL_8088 || !this.segSS.fExpDown && this.segSS.limit == this.segSS.maskAddr || this.segSS.fExpDown && !this.segSS.limit) {
this.setSP((regLSP - this.segSS.base) & this.segSS.maskAddr);
regLSP = this.regLSP;
} else {
X86.helpFault.call(this, X86.EXCEPTION.SS_FAULT, 0);
}
}
switch(size) {
case 1:
this.setByte(regLSP, d);
break;
case 2:
this.setShort(regLSP, d);
break;
case 4:
this.setLong(regLSP, d);
break;
default:
this.assert(false);
break;
}
/*
* We update this.regLSP at the end to make life simpler for opcode handlers that perform only one
* pushWord() operation, relieving them from having to snapshot this.regLSP into this.opLSP needlessly.
*/
this.regLSP = regLSP;
}
/**
* pushWord(w)
*
* NOTE: pushWord() used to do a simplified version of pushData(), and while that might have made the emulator
* slightly faster, it was woefully duplicative. Let's trust the combination of the Closure Compiler and the
* JavaScript engines to automatically inline instead.
*
* @this {X86CPU}
* @param {number} w is the word (16-bit) value to push at current SP; SP decreased by 2 or 4
*/
pushWord(w)
{
/*
* This assertion is no longer valid, now that we've fixed opPUSH8() to use getIPDisp() instead of getIPByte(),
* thus sign-extending the byte as appropriate. And since sign-extension necessarily affects the entire 32-bit
* value, this assertion could fail when dataMask is 16 bits.
*
* this.assert((w & this.maskData) == w);
*
* setWord() calls setShort() or setLong() as appropriate, and setShort() truncates incoming values, so the fact
* that any incoming signed values will not be truncated to 16 bits should not be a concern.
*/
var regLSP = (this.regLSP - (I386? this.sizeData : 2))|0;
this.pushData(w, I386? this.sizeData : 2);
}
/**
* pushData(data, width, size)
*
* The size parameter serves two very limited purposes: 1) the ability to push data according to a previous
* operand size, and 2) the ability to write fewer bytes than the width if necessary.
*
* The former occurs when a 32-bit code segment performs a 16:32 call to a 16-bit code segment; after the
* new 16-bit code segment is loaded (and possible stack switch occurs), the return address (both segment
* and offset) must still be pushed as 32-bit values.
*
* The latter occurs with segment register pushes. When a 32-bit operand size is in effect (ie, width is 4),
* only the low 16 bits should be written (size must be 2).
*
* For all other kinds of pushes, width and size are impliedly the same.
*
* @this {X86CPU}
* @param {number} data is the data to push at current SP; SP decreased by size
* @param {number} width is the width of the data to push, in bytes (must be either 2 or 4)
* @param {number} [size] is the size of the data to push, in bytes (must be 1, 2, or 4, and <= width)
*/
pushData(data, width, size = width)
{
this.assert((width == 2 || width == 4) && (size > 0 && size <= width));
var regLSP = (this.regLSP - width)|0;
/*
* Properly comparing regLSP to regLSPLimitLow would normally require coercing both to unsigned
* (ie, floating-point) values. But instead, we do a subtraction, (regLSP - regLSPLimitLow), and
* if the result is negative, we need only be concerned if the signs of both numbers are the same
* (ie, the sign of their XOR'ed union is positive).
* Comparing regLSP to regLSPLimitLow requires coercing both to unsigned (ie, floating-point) values.
* If we didn't, when we subtracted a 32-bit limit like 0xFFFFFFF0 (-16) from a 32-bit value like 0x1,
* we would have a positive result, even though the value was well below the limit.
*/
if (((regLSP - this.regLSPLimitLow)|0) < 0 && (this.regLSPLimitLow ^ regLSP) >= 0) {
var delta = (regLSP >>> 0) - (this.regLSPLimitLow >>> 0);
if (delta < 0) {
/*
* There's no such thing as an SS fault on the 8086/8088, and I'm assuming that, on newer
* processors, when the stack segment limit is set to the maximum, it's OK for the stack to wrap.
* There's no such thing as an SS fault on the 8086/8088, and in fact, we have to support the
* operation even when the address straddles the wrap boundary (ie, when delta is -1); other
* emulators tend to barf on a wrap, usually because they're running in V86 mode instead of real mode.
*/
if (this.model <= X86.MODEL_8088 || !this.segSS.fExpDown && this.segSS.limit == this.segSS.maskAddr || this.segSS.fExpDown && !this.segSS.limit) {
if (this.model <= X86.MODEL_8088) {
if (delta == -1) {
this.setByte(regLSP + 1, data >> 8);
this.setSP((regLSP - this.segSS.base) & this.segSS.maskAddr);
this.setByte(this.regLSP, data);
return;
}
this.assert(!this.segSS.fExpDown && this.segSS.limit == this.segSS.maskAddr);
}
/*
* I'm assuming that, on newer processors, when the stack segment limit is set to the maximum,
* it's OK for the stack to wrap, unless the new address is straddling the wrap boundary (ie, when
* delta is < 0 and > -width).
*/
if (!this.segSS.fExpDown && this.segSS.limit == this.segSS.maskAddr || this.segSS.fExpDown && !this.segSS.limit) {
if (delta < 0 && delta > -width) {
X86.helpFault.call(this, X86.EXCEPTION.SS_FAULT, 0);
return;
}
this.setSP((regLSP - this.segSS.base) & this.segSS.maskAddr);
regLSP = this.regLSP;
} else {
X86.helpFault.call(this, X86.EXCEPTION.SS_FAULT, 0);
return;
}
}
this.setWord(regLSP, w);
switch(size) {
case 1:
this.setByte(regLSP, data);
break;
case 2:
this.setShort(regLSP, data);
break;
case 4:
this.setLong(regLSP, data);
break;
default:
this.assert(false);
break;
}
/*
* We update this.regLSP at the end to make life simpler for opcode handlers that perform only one

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -12146,11 +12146,20 @@ class CPU extends Component {
case "run":
this.bindings[sBinding] = control;
control.onclick = function onClickRun() {
var fRunning = cpu.flags.running;
if (!cpu.cmp || !cpu.cmp.checkPower()) return;
if (!cpu.flags.running)
cpu.runCPU(true);
else
cpu.stopCPU(true);
/*
* We snapped the CPU's running flag before calling checkPower() because there are rare (REPOWER)
* situations where checkPower() will have started the CPU as well. So toggle the CPU state ONLY
* if the running flag remains unchanged.
*/
if (fRunning == cpu.flags.running) {
if (!cpu.flags.running) {
cpu.runCPU(true);
} else {
cpu.stopCPU(true);
}
}
};
fBound = true;
break;
@ -18237,140 +18246,141 @@ class X86CPU extends CPU {
popWord()
{
var w = this.getWord(this.regLSP);
this.regLSP = (this.regLSP + (I386? this.sizeData : 2))|0;
/*
* Properly comparing regLSP to regLSPLimit would normally require coercing both to unsigned
* (ie, floating-point) values. But instead, we do a subtraction, (regLSPLimit - regLSP), and
* if the result is negative, we need only be concerned if the signs of both numbers are the same
* (ie, the sign of their XOR'ed union is positive).
*
* TODO: I'm combining the old 8088 address-wrap check with the new segment-limit check,
* even though the correct time to do the latter is immediately BEFORE the fetch, not AFTER;
* I'm working around this for now by applying a -1 fudge factor to the fault check below.
* Comparing regLSP to regLSPLimit requires coercing both to unsigned (ie, floating-point) values.
* If we didn't, when we subtracted a 32-bit value like 0x1 from a 32-bit limit like 0xFFFFFFF0 (-16),
* we would have a negative result, even though the value was well below the limit.
*/
var off = ((this.regLSPLimit - this.regLSP)|0);
if (off < 0 && (this.regLSPLimit ^ this.regLSP) >= 0) {
var delta = (this.regLSPLimit >>> 0) - (this.regLSP >>> 0);
if (delta < 0) {
/*
* There's no such thing as an SS fault on the 8086/8088, and I'm assuming that, on newer
* processors, when the stack segment limit is set to the maximum, it's OK for the stack to wrap.
* There's no such thing as an SS fault on the 8086/8088, and in fact, we have to support the
* operation even when the address straddles the wrap boundary; other emulators tend to barf on
* a wrap, usually because they're running in V86 mode instead of real mode.
*/
if (this.model <= X86.MODEL_8088 || !this.segSS.fExpDown && this.segSS.limit == this.segSS.maskAddr || this.segSS.fExpDown && !this.segSS.limit) {
if (this.model <= X86.MODEL_8088) {
this.setSP((this.regLSP - this.segSS.base) & this.segSS.maskAddr);
} else if (off < -1) { // fudge factor
X86.helpFault.call(this, X86.EXCEPTION.SS_FAULT, 0);
if (delta < -1) {
w = (w & 0xff) | (this.getByte(this.regLSP - 1) << 8);
}
}
else {
/*
* I'm assuming that, on newer processors, when the stack segment limit is set to the maximum,
* it's OK for the stack to wrap, unless the new address is straddling the wrap boundary (ie, when
* delta is < 0 and > -sizeData).
*/
if (!this.segSS.fExpDown && this.segSS.limit == this.segSS.maskAddr || this.segSS.fExpDown && !this.segSS.limit) {
this.setSP((this.regLSP - this.segSS.base) & this.segSS.maskAddr);
} else {
/*
* TODO: I'm combining the old 8088 address-wrap check with the new segment-limit check, even though the
* correct time to do the latter is immediately BEFORE the fetch, not AFTER; I'm working around this for now
* by applying a -1 fudge factor to the following fault check.
*/
if (delta < -1) {
X86.helpFault.call(this, X86.EXCEPTION.SS_FAULT, 0);
}
}
}
}
return w;
}
/**
* pushData(d, width, size)
*
* This function serves two very limited purposes: 1) the ability to push data according to a previous
* operand size (width), and 2) the ability to write fewer bytes than the width if necessary (size).
*
* The former occurs when a 32-bit code segment performs a 16:32 call to a 16-bit code segment; after the
* new 16-bit code segment is loaded (and possible stack switch occurs), the return address (both segment
* and offset) must still be pushed as 32-bit values.
*
* The latter occurs with segment register pushes. When a 32-bit operand size is in effect (ie, width is 4),
* only the low 16 bits should be written (size must be 2). For all other kinds of pushes, width and size are
* impliedly the same.
*
* @this {X86CPU}
* @param {number} d is the data to push at current SP; SP decreased by size
* @param {number} width is the width of the data to push, in bytes (must be either 2 or 4)
* @param {number} size is the size of the data to push, in bytes (must be 1, 2, or 4, and <= width)
*/
pushData(d, width, size)
{
var regLSP = (this.regLSP - width)|0;
/*
* Properly comparing regLSP to regLSPLimitLow would normally require coercing both to unsigned
* (ie, floating-point) values. But instead, we do a subtraction, (regLSP - regLSPLimitLow), and
* if the result is negative, we need only be concerned if the signs of both numbers are the same
* (ie, the sign of their XOR'ed union is positive).
*/
if (((regLSP - this.regLSPLimitLow)|0) < 0 && (this.regLSPLimitLow ^ regLSP) >= 0) {
/*
* There's no such thing as an SS fault on the 8086/8088, and I'm assuming that, on newer
* processors, when the stack segment limit is set to the maximum, it's OK for the stack to wrap.
*/
if (this.model <= X86.MODEL_8088 || !this.segSS.fExpDown && this.segSS.limit == this.segSS.maskAddr || this.segSS.fExpDown && !this.segSS.limit) {
this.setSP((regLSP - this.segSS.base) & this.segSS.maskAddr);
regLSP = this.regLSP;
} else {
X86.helpFault.call(this, X86.EXCEPTION.SS_FAULT, 0);
}
}
switch(size) {
case 1:
this.setByte(regLSP, d);
break;
case 2:
this.setShort(regLSP, d);
break;
case 4:
this.setLong(regLSP, d);
break;
default:
break;
}
/*
* We update this.regLSP at the end to make life simpler for opcode handlers that perform only one
* pushWord() operation, relieving them from having to snapshot this.regLSP into this.opLSP needlessly.
*/
this.regLSP = regLSP;
}
/**
* pushWord(w)
*
* NOTE: pushWord() used to do a simplified version of pushData(), and while that might have made the emulator
* slightly faster, it was woefully duplicative. Let's trust the combination of the Closure Compiler and the
* JavaScript engines to automatically inline instead.
*
* @this {X86CPU}
* @param {number} w is the word (16-bit) value to push at current SP; SP decreased by 2 or 4
*/
pushWord(w)
{
/*
* This assertion is no longer valid, now that we've fixed opPUSH8() to use getIPDisp() instead of getIPByte(),
* thus sign-extending the byte as appropriate. And since sign-extension necessarily affects the entire 32-bit
* value, this assertion could fail when dataMask is 16 bits.
*
*
*
* setWord() calls setShort() or setLong() as appropriate, and setShort() truncates incoming values, so the fact
* that any incoming signed values will not be truncated to 16 bits should not be a concern.
*/
var regLSP = (this.regLSP - (I386? this.sizeData : 2))|0;
this.pushData(w, I386? this.sizeData : 2);
}
/**
* pushData(data, width, size)
*
* The size parameter serves two very limited purposes: 1) the ability to push data according to a previous
* operand size, and 2) the ability to write fewer bytes than the width if necessary.
*
* The former occurs when a 32-bit code segment performs a 16:32 call to a 16-bit code segment; after the
* new 16-bit code segment is loaded (and possible stack switch occurs), the return address (both segment
* and offset) must still be pushed as 32-bit values.
*
* The latter occurs with segment register pushes. When a 32-bit operand size is in effect (ie, width is 4),
* only the low 16 bits should be written (size must be 2).
*
* For all other kinds of pushes, width and size are impliedly the same.
*
* @this {X86CPU}
* @param {number} data is the data to push at current SP; SP decreased by size
* @param {number} width is the width of the data to push, in bytes (must be either 2 or 4)
* @param {number} [size] is the size of the data to push, in bytes (must be 1, 2, or 4, and <= width)
*/
pushData(data, width, size = width)
{
var regLSP = (this.regLSP - width)|0;
/*
* Properly comparing regLSP to regLSPLimitLow would normally require coercing both to unsigned
* (ie, floating-point) values. But instead, we do a subtraction, (regLSP - regLSPLimitLow), and
* if the result is negative, we need only be concerned if the signs of both numbers are the same
* (ie, the sign of their XOR'ed union is positive).
* Comparing regLSP to regLSPLimitLow requires coercing both to unsigned (ie, floating-point) values.
* If we didn't, when we subtracted a 32-bit limit like 0xFFFFFFF0 (-16) from a 32-bit value like 0x1,
* we would have a positive result, even though the value was well below the limit.
*/
if (((regLSP - this.regLSPLimitLow)|0) < 0 && (this.regLSPLimitLow ^ regLSP) >= 0) {
var delta = (regLSP >>> 0) - (this.regLSPLimitLow >>> 0);
if (delta < 0) {
/*
* There's no such thing as an SS fault on the 8086/8088, and I'm assuming that, on newer
* processors, when the stack segment limit is set to the maximum, it's OK for the stack to wrap.
* There's no such thing as an SS fault on the 8086/8088, and in fact, we have to support the
* operation even when the address straddles the wrap boundary (ie, when delta is -1); other
* emulators tend to barf on a wrap, usually because they're running in V86 mode instead of real mode.
*/
if (this.model <= X86.MODEL_8088 || !this.segSS.fExpDown && this.segSS.limit == this.segSS.maskAddr || this.segSS.fExpDown && !this.segSS.limit) {
if (this.model <= X86.MODEL_8088) {
if (delta == -1) {
this.setByte(regLSP + 1, data >> 8);
this.setSP((regLSP - this.segSS.base) & this.segSS.maskAddr);
this.setByte(this.regLSP, data);
return;
}
}
/*
* I'm assuming that, on newer processors, when the stack segment limit is set to the maximum,
* it's OK for the stack to wrap, unless the new address is straddling the wrap boundary (ie, when
* delta is < 0 and > -width).
*/
if (!this.segSS.fExpDown && this.segSS.limit == this.segSS.maskAddr || this.segSS.fExpDown && !this.segSS.limit) {
if (delta < 0 && delta > -width) {
X86.helpFault.call(this, X86.EXCEPTION.SS_FAULT, 0);
return;
}
this.setSP((regLSP - this.segSS.base) & this.segSS.maskAddr);
regLSP = this.regLSP;
} else {
X86.helpFault.call(this, X86.EXCEPTION.SS_FAULT, 0);
return;
}
}
this.setWord(regLSP, w);
switch(size) {
case 1:
this.setByte(regLSP, data);
break;
case 2:
this.setShort(regLSP, data);
break;
case 4:
this.setLong(regLSP, data);
break;
default:
break;
}
/*
* We update this.regLSP at the end to make life simpler for opcode handlers that perform only one
@ -48883,10 +48893,10 @@ class Video extends Component {
* is exasperating; browsers can't agree on 'full' or 'Full, 'request' or 'Request', 'screen' or 'Screen', and
* while some browsers honor other browser prefixes, most browsers don't.
*/
this.doFullScreen = null;
if ((this.container = container)) {
this.doFullScreen = container['requestFullscreen'] || container['msRequestFullscreen'] || container['mozRequestFullScreen'] || container['webkitRequestFullscreen'];
if (this.doFullScreen) {
this.container = container;
if (this.container) {
this.container.doFullScreen = container['requestFullscreen'] || container['msRequestFullscreen'] || container['mozRequestFullScreen'] || container['webkitRequestFullscreen'];
if (this.container.doFullScreen) {
for (i = 0; i < asWebPrefixes.length; i++) {
sEvent = asWebPrefixes[i] + 'fullscreenchange';
if ('on' + sEvent in document) {
@ -49102,7 +49112,7 @@ class Video extends Component {
switch (sBinding) {
case "fullScreen":
if (this.doFullScreen) {
if (this.container && this.container.doFullScreen) {
control.onclick = function onClickFullScreen() {
if (DEBUG) video.printMessage("fullScreen()");
video.goFullScreen();
@ -49188,7 +49198,7 @@ class Video extends Component {
{
var fSuccess = false;
if (this.container) {
if (this.doFullScreen) {
if (this.container.doFullScreen) {
/*
* Styling the container with a width of "100%" and a height of "auto" works great when the aspect ratio
* of our virtual screen is at least roughly equivalent to the physical screen's aspect ratio, but now that
@ -49239,7 +49249,7 @@ class Video extends Component {
this.canvasScreen.style.margin = "auto";
}
this.container.style.backgroundColor = this.colorScreen;
this.doFullScreen();
this.container.doFullScreen();
fSuccess = true;
}
this.setFocus();
@ -75087,6 +75097,28 @@ class Computer extends Component {
*/
checkPower()
{
if (this.flags.unloading) {
/*
* We happen to know that we're currently only called by the CPU's onClickRun() function, so
* if the unloading flag is set, then we've somehow gotten into a weird state where the machine
* thinks it's being (or has been) unloaded by the browser, but in fact, it has not.
*
* The only time I've seen this happen is when the user clicks a link on a page that the browser
* decided to treat as a download operation, instead of loading a new page. The proper way to
* resolve that confusion is to set the "download" attribute on the link (which will prevent the
* page's "onbeforeunload" handler from being called in the first place), but we cannot guarantee
* that all such links will have their "download" attribute properly set.
*
* Hence, this code: we do the same thing that the show() function does, which is to attempt a
* REPOWER operation. If that doesn't result in the powered flag getting turned back on, well,
* then we're probably screwed.
*/
this.flags.unloading = false;
if (this.flags.initDone && !this.flags.powered) {
this.powerOn(Computer.RESUME_REPOWER);
}
}
if (this.flags.powered) return true;
var component = null, iComponent;
@ -75897,6 +75929,9 @@ class Computer extends Component {
var computer = /** @type {Computer} */ (Component.getComponentByType("Computer", parmsComputer['id']));
if (computer) {
/*
* Clear new flag that Component functions (eg, notice()) should check before alerting the user.
*/
computer.flags.unloading = false;
if (DEBUG && computer.messageEnabled()) {
@ -75904,7 +75939,7 @@ class Computer extends Component {
}
if (computer.flags.initDone && !computer.flags.powered) {
/**
/*
* Repower the computer, notifying every component to continue running as-is.
*/
computer.powerOn(Computer.RESUME_REPOWER);
@ -75949,7 +75984,7 @@ class Computer extends Component {
if (computer) {
/*
* Added a new flag that Component functions (eg, notice()) should check before alerting the user.
* Set new flag that Component functions (eg, notice()) should check before alerting the user.
*/
computer.flags.unloading = true;

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long