Added WDEB386 service simulation (INT 0x41)

This commit is contained in:
Jeff Parsons 2015-08-27 16:23:12 -07:00
commit f56815c11b
52 changed files with 357 additions and 58 deletions

View file

@ -0,0 +1,5 @@
Windows 95 Test Machine
---
[Embedded DeskPro 386](machine.xml "PCjs:deskpro386:::debugger")

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/versions/pcjs/1.19.2/machine.xsl"?>
<machine id="deskpro386" class="pc" border="1" pos="center" background="#FAEBD7">
<computer id="deskpro386-vga-4096k" name="Compaq DeskPro 386" buswidth="32" state="/devices/pc/machine/compaq/deskpro386/vga/4096kb/state.json"/>
<computer id="deskpro386-vga-4096k" name="Compaq DeskPro 386" buswidth="32"/>
<cpu id="cpu386" model="80386" autostart="false"/>
<ram id="ramLow" addr="0x00000" test="false" size="0xa0000" comment="ROM BIOS memory test has been disabled"/>
<ram id="ramCPQ" addr="0xfa0000" size="0x60000" comment="Compaq memory at 0xFA0000"/>
@ -10,7 +10,7 @@
<rom id="romBIOS" addr="0xf8000" size="0x8000" alias="[0xf0000,0xffff0000,0xffff8000]" file="/devices/pc/bios/compaq/deskpro386/1988-01-28/1988-01-28.json"/>
<video ref="/devices/pc/video/ibm/vga/ibm-vga-lockfs.xml"/>
<keyboard id="keyboard"/>
<fdc ref="/disks/pc/library.xml" automount='{B: {name: "Win95 Build 499 (Disk 1)", path: "/disks/pc/windows/win95/build499/WIN95-DISK01.json"}}'/>
<fdc ref="/disks/pc/library.xml" automount='{B: {name: "Windows 95 (Disk 1)", path: "/disks/pc/windows/win95/4.00.950/WIN95-DISK01.json"}}'/>
<debugger id="debugger" messages="" commands=''/>
<panel ref="/devices/pc/panel/wide386.xml"/>
<hdc id="hdcAT" type="at" drives='[{name:"68Mb Hard Disk",type:4,path:"http://static.pcjs.org/devices/pc/machine/compaq/deskpro386/vga/4096kb/WDEB386-68Mb.json"}]'/>

View file

@ -36,7 +36,8 @@
<manifest ref="/disks/pc/windows/1.04/manifest.xml" disk="*"/>
<manifest ref="/disks/pc/windows/2.03/manifest.xml" disk="*"/>
<manifest ref="/disks/pc/windows/3.00/manifest.xml" disk="*"/>
<manifest ref="/disks/pc/windows/win95/build499/manifest.xml" disk="*"/>
<manifest ref="/disks/pc/windows/win95/4.00.499/manifest.xml" disk="*"/>
<manifest ref="/disks/pc/windows/win95/4.00.950/manifest.xml" disk="*"/>
<manifest ref="/disks/pc/minix/1.1/manifest.xml" disk="*"/>
<manifest ref="/disks/pc/unix/ibm/pcix/manifest.xml" disk="*"/>
<manifest ref="/disks/pc/unix/microport/system-v/2.3/manifest.xml" disk="*"/>

View file

@ -2,43 +2,48 @@
<?xml-stylesheet type="text/xsl" href="/versions/pcjs/1.19.2/manifest.xsl"?>
<manifest type="software">
<title>Windows 95 (Build 499)</title>
<disk id="disk01" size="1474560" chs="80:2:18" img="../static/build499/WIN95-DISK01.img" href="/disks/pc/windows/win95/build499/WIN95-DISK01.json" md5="732d1cb011be22d1beda31f4dcd8ea56" md5json="6fa3bc43a08502be56bcf765c2470c35">
<version>4.00.499</version>
<type>Windows</type>
<category>Operating System</category>
<author>Microsoft</author>
<releaseDate>June 16, 1995</releaseDate>
<disk id="disk01" size="1474560" chs="80:2:18" img="../static/4.00.499/WIN95-DISK01.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK01.json" md5="732d1cb011be22d1beda31f4dcd8ea56" md5json="6fa3bc43a08502be56bcf765c2470c35">
<name>Win95 Build 499 (Disk 1)</name>
</disk>
<disk id="disk02" size="1720320" chs="80:2:21" img="../static/build499/WIN95-DISK02.img" href="/disks/pc/windows/win95/build499/WIN95-DISK02.json" md5="3c4ff0741307c736fd956447b82db041" md5json="5688fde3e3f978e4d31127b118383f79">
<disk id="disk02" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK02.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK02.json" md5="3c4ff0741307c736fd956447b82db041" md5json="5688fde3e3f978e4d31127b118383f79">
<name>Win95 Build 499 (Disk 2)</name>
</disk>
<disk id="disk03" size="1720320" chs="80:2:21" img="../static/build499/WIN95-DISK03.img" href="/disks/pc/windows/win95/build499/WIN95-DISK03.json" md5="7c635a4d309ecc182db99dd3e6642bac" md5json="939be24d14aff97578200c8429ca4a05">
<disk id="disk03" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK03.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK03.json" md5="7c635a4d309ecc182db99dd3e6642bac" md5json="939be24d14aff97578200c8429ca4a05">
<name>Win95 Build 499 (Disk 3)</name>
</disk>
<disk id="disk04" size="1720320" chs="80:2:21" img="../static/build499/WIN95-DISK04.img" href="/disks/pc/windows/win95/build499/WIN95-DISK04.json" md5="59e781f887857883108d3e0a4ea338bc" md5json="4f62253c0731ac0d87d6cdbdc218a921">
<disk id="disk04" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK04.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK04.json" md5="59e781f887857883108d3e0a4ea338bc" md5json="4f62253c0731ac0d87d6cdbdc218a921">
<name>Win95 Build 499 (Disk 4)</name>
</disk>
<disk id="disk05" size="1720320" chs="80:2:21" img="../static/build499/WIN95-DISK05.img" href="/disks/pc/windows/win95/build499/WIN95-DISK05.json" md5="4866930efb5198e6e9c9ea6958989547" md5json="e9b2b53575ee7ca1546be36f9c36d143">
<disk id="disk05" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK05.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK05.json" md5="4866930efb5198e6e9c9ea6958989547" md5json="e9b2b53575ee7ca1546be36f9c36d143">
<name>Win95 Build 499 (Disk 5)</name>
</disk>
<disk id="disk06" size="1720320" chs="80:2:21" img="../static/build499/WIN95-DISK06.img" href="/disks/pc/windows/win95/build499/WIN95-DISK06.json" md5="99d60c50db21206908d569db0d859f5d" md5json="48aa2717c9cbcc46639cef839eed5378">
<disk id="disk06" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK06.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK06.json" md5="99d60c50db21206908d569db0d859f5d" md5json="48aa2717c9cbcc46639cef839eed5378">
<name>Win95 Build 499 (Disk 6)</name>
</disk>
<disk id="disk07" size="1720320" chs="80:2:21" img="../static/build499/WIN95-DISK07.img" href="/disks/pc/windows/win95/build499/WIN95-DISK07.json" md5="c4eb6a910b5310427e3099c079c62261" md5json="75f2d3b963e81c1b37c725f350971562">
<disk id="disk07" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK07.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK07.json" md5="c4eb6a910b5310427e3099c079c62261" md5json="75f2d3b963e81c1b37c725f350971562">
<name>Win95 Build 499 (Disk 7)</name>
</disk>
<disk id="disk08" size="1720320" chs="80:2:21" img="../static/build499/WIN95-DISK08.img" href="/disks/pc/windows/win95/build499/WIN95-DISK08.json" md5="d6ba0299f3f02851ac2cc44ed54dbcc3" md5json="2b89cfd0f05934bdc4cca15064f0d7d4">
<disk id="disk08" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK08.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK08.json" md5="d6ba0299f3f02851ac2cc44ed54dbcc3" md5json="2b89cfd0f05934bdc4cca15064f0d7d4">
<name>Win95 Build 499 (Disk 8)</name>
</disk>
<disk id="disk09" size="1720320" chs="80:2:21" img="../static/build499/WIN95-DISK09.img" href="/disks/pc/windows/win95/build499/WIN95-DISK09.json" md5="308387d3c51e837fd7869a7b0b44a3cb" md5json="4a86ce9737eb664450c351fb274f940c">
<disk id="disk09" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK09.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK09.json" md5="308387d3c51e837fd7869a7b0b44a3cb" md5json="4a86ce9737eb664450c351fb274f940c">
<name>Win95 Build 499 (Disk 9)</name>
</disk>
<disk id="disk10" size="1720320" chs="80:2:21" img="../static/build499/WIN95-DISK10.img" href="/disks/pc/windows/win95/build499/WIN95-DISK10.json" md5="1cc5e299dfb83dd555227ad9546393fe" md5json="dbee2d4261d25c235f01278fded36a0b">
<disk id="disk10" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK10.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK10.json" md5="1cc5e299dfb83dd555227ad9546393fe" md5json="dbee2d4261d25c235f01278fded36a0b">
<name>Win95 Build 499 (Disk 10)</name>
</disk>
<disk id="disk11" size="1720320" chs="80:2:21" img="../static/build499/WIN95-DISK11.img" href="/disks/pc/windows/win95/build499/WIN95-DISK11.json" md5="abe21872967030c77c4b1c5acc330944" md5json="40d23db1b9fd26cb728854aaf3a1d4f8">
<disk id="disk11" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK11.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK11.json" md5="abe21872967030c77c4b1c5acc330944" md5json="40d23db1b9fd26cb728854aaf3a1d4f8">
<name>Win95 Build 499 (Disk 11)</name>
</disk>
<disk id="disk12" size="1720320" chs="80:2:21" img="../static/build499/WIN95-DISK12.img" href="/disks/pc/windows/win95/build499/WIN95-DISK12.json" md5="55a8eabe146455de6d724912608c4dae" md5json="f609a685c6a4e98447193a969d342a10">
<disk id="disk12" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK12.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK12.json" md5="55a8eabe146455de6d724912608c4dae" md5json="f609a685c6a4e98447193a969d342a10">
<name>Win95 Build 499 (Disk 12)</name>
</disk>
<disk id="disk13" size="1720320" chs="80:2:21" img="../static/build499/WIN95-DISK13.img" href="/disks/pc/windows/win95/build499/WIN95-DISK13.json" md5="9842dbeabf3b7dc98ee727467c81cef6" md5json="4de833b8106fa20db8b760c2c2633123">
<disk id="disk13" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK13.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK13.json" md5="9842dbeabf3b7dc98ee727467c81cef6" md5json="4de833b8106fa20db8b760c2c2633123">
<name>Win95 Build 499 (Disk 13)</name>
</disk>
</manifest>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/versions/pcjs/1.19.2/manifest.xsl"?>
<manifest type="software">
<title>Windows 95 (RTM)</title>
<version>4.00.950</version>
<type>Windows</type>
<category>Operating System</category>
<author>Microsoft</author>
<releaseDate>August 24, 1995</releaseDate>
<disk id="disk00" size="1474560" chs="80:2:18" img="../static/4.00.950/WIN95-BOOT.img" href="/disks/pc/windows/win95/4.00.950/WIN95-BOOT.json" md5="666f0f99b650468aaba0eb4ca17d519d" md5json="abe8b98d12847534c56dbd66cc1d32cc">
<name>Windows 95 (Boot)</name>
</disk>
<disk id="disk01" size="1474560" chs="80:2:18" img="../static/4.00.950/WIN95-DISK01.img" href="/disks/pc/windows/win95/4.00.950/WIN95-DISK01.json" md5="fd17fcf71afc246afbdf7b95ef1952ca" md5json="e1960eb29c99ebc5fb706d81b3510fca">
<name>Windows 95 (Disk 1)</name>
</disk>
<disk id="disk02" size="1720320" chs="80:2:21" img="../static/4.00.950/WIN95-DISK02.img" href="/disks/pc/windows/win95/4.00.950/WIN95-DISK02.json" md5="5157c8e1859abd72bf79b1177da83831" md5json="49154d57bd7ed3f9db49e83314732521">
<name>Windows 95 (Disk 2)</name>
</disk>
<disk id="disk03" size="1720320" chs="80:2:21" img="../static/4.00.950/WIN95-DISK03.img" href="/disks/pc/windows/win95/4.00.950/WIN95-DISK03.json" md5="c2a49d114e118ff0daa3e196c9da3968" md5json="24b72db4c4bd1b90744f6b4d43097ea2">
<name>Windows 95 (Disk 3)</name>
</disk>
<disk id="disk04" size="1720320" chs="80:2:21" img="../static/4.00.950/WIN95-DISK04.img" href="/disks/pc/windows/win95/4.00.950/WIN95-DISK04.json" md5="1129e79622d038fd7aea4fff483d284b" md5json="48ab9a2f12c7a388b4f14445245b2f46">
<name>Windows 95 (Disk 4)</name>
</disk>
<disk id="disk05" size="1720320" chs="80:2:21" img="../static/4.00.950/WIN95-DISK05.img" href="/disks/pc/windows/win95/4.00.950/WIN95-DISK05.json" md5="dcebc4e3a30ea48de3ac2a7599677383" md5json="95099bb2c07076e3225f5f124d528486">
<name>Windows 95 (Disk 5)</name>
</disk>
<disk id="disk06" size="1720320" chs="80:2:21" img="../static/4.00.950/WIN95-DISK06.img" href="/disks/pc/windows/win95/4.00.950/WIN95-DISK06.json" md5="fe7a56694b9a5f58188e1b4eabe6f0c0" md5json="5f1f3477680bf2700973f4ba2e0616ce">
<name>Windows 95 (Disk 6)</name>
</disk>
<disk id="disk07" size="1720320" chs="80:2:21" img="../static/4.00.950/WIN95-DISK07.img" href="/disks/pc/windows/win95/4.00.950/WIN95-DISK07.json" md5="54711b87d067a2181136f12c6df00e97" md5json="041a7419b80db60742b22429af7e9d5b">
<name>Windows 95 (Disk 7)</name>
</disk>
<disk id="disk08" size="1720320" chs="80:2:21" img="../static/4.00.950/WIN95-DISK08.img" href="/disks/pc/windows/win95/4.00.950/WIN95-DISK08.json" md5="87c79d75131162e5e77daf0978e8c8c5" md5json="397f30c00ce17a180a49af8b45872ed3">
<name>Windows 95 (Disk 8)</name>
</disk>
<disk id="disk09" size="1720320" chs="80:2:21" img="../static/4.00.950/WIN95-DISK09.img" href="/disks/pc/windows/win95/4.00.950/WIN95-DISK09.json" md5="3dae8277921b8847648b7aec249809ef" md5json="21f16a83e98bd9277866c3f46b101235">
<name>Windows 95 (Disk 9)</name>
</disk>
<disk id="disk10" size="1720320" chs="80:2:21" img="../static/4.00.950/WIN95-DISK10.img" href="/disks/pc/windows/win95/4.00.950/WIN95-DISK10.json" md5="bb8f2d758a827adce0dcd02fb786fd46" md5json="cdf052957fd841a06813ad97712a7e7e">
<name>Windows 95 (Disk 10)</name>
</disk>
<disk id="disk11" size="1720320" chs="80:2:21" img="../static/4.00.950/WIN95-DISK11.img" href="/disks/pc/windows/win95/4.00.950/WIN95-DISK11.json" md5="cc8a702107e486917046b991c7ef3399" md5json="3d71b4718277848dac72469ec00f67df">
<name>Windows 95 (Disk 11)</name>
</disk>
<disk id="disk12" size="1720320" chs="80:2:21" img="../static/4.00.950/WIN95-DISK12.img" href="/disks/pc/windows/win95/4.00.950/WIN95-DISK12.json" md5="2cc93051ae90927ec13c4962c69162c9" md5json="d45232d4318db466022a58a46879ce47">
<name>Windows 95 (Disk 12)</name>
</disk>
<disk id="disk13" size="1720320" chs="80:2:21" img="../static/4.00.950/WIN95-DISK13.img" href="/disks/pc/windows/win95/4.00.950/WIN95-DISK13.json" md5="40c5970f44ad040690a2db570b3a9a40" md5json="60f10fc42a44e248c63e553665b104c8">
<name>Windows 95 (Disk 13)</name>
</disk>
</manifest>

View file

@ -311,7 +311,7 @@ Bus.prototype.reset = function()
* powerUp(data, fRepower)
*
* We don't need a powerDown() handler, because for largely historical reasons, our state (including the A20 state)
* is saved by saveMemory().
* is saved by the saveMemory(), which called by the CPU.
*
* However, we do need a powerUp() handler, because on resumable machines, the Computer's onReset() function calls
* everyone's powerUp() handler rather than their reset() handler.

View file

@ -1095,7 +1095,7 @@ ChipSet.prototype.powerUp = function(data, fRepower)
* powerDown(fSave, fShutdown)
*
* @this {ChipSet}
* @param {boolean} fSave
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/

View file

@ -766,9 +766,9 @@ Computer.prototype.powerReport = function(stateComputer)
* which doesn't seem like a huge problem.
*
* @this {Computer}
* @param {boolean} fSave
* @param {boolean} [fSave] is true to request a saved state
* @param {boolean} [fShutdown] is true if the machine is being shut down
* @return {string|null} string representing the captured state (or null if error)
* @return {string|null} string representing the saved state (or null if error)
*/
Computer.prototype.powerOff = function(fSave, fShutdown)
{
@ -966,7 +966,14 @@ Computer.prototype.setBinding = function(sHTMLType, sBinding, control)
control.onclick = function onClickSave() {
var sUserID = computer.queryUserID(true);
if (sUserID) {
var fSave = !!(computer.resume && !computer.sResumePath);
/*
* I modified the test to include a check for sStatePath so that I could save new states
* for machines with existing states; otherwise, I'd have no (easy) way of capturing and
* updating their state. Making the machine (even temporarily) resumable would have been
* one work-around, but it's not appropriate for some machines, as their state is simply
* too large (for localStorage anyway, which is the default storage solution).
*/
var fSave = !!(computer.resume && !computer.sResumePath || computer.sStatePath);
var sState = computer.powerOff(fSave);
if (fSave) {
computer.saveServerState(sUserID, sState);
@ -974,6 +981,19 @@ Computer.prototype.setBinding = function(sHTMLType, sBinding, control)
computer.notice("Resume disabled, machine state not saved");
}
}
/*
* This seemed like a handy alternative, but it turned out to be a no-go, at least for large states:
*
* var sState = computer.powerOff(true);
* if (sState) {
* sState = "data:text/json;charset=utf-8," + encodeURIComponent(sState);
* window.open(sState);
* }
*
* Perhaps if I embedded the data in a link on the current page instead; eg:
*
* $('<a href="' + sState + '" download="state.json">Download</a>').appendTo('#container');
*/
};
return true;
case "reset":

View file

@ -287,7 +287,7 @@ CPU.prototype.powerUp = function(data, fRepower)
* powerDown(fSave, fShutdown)
*
* @this {CPU}
* @param {boolean} fSave
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/

View file

@ -1247,9 +1247,133 @@ if (DEBUGGER) {
this.messageDump(Messages.TSS, function onDumpTSS(s) { dbg.dumpTSS(s); });
this.messageDump(Messages.DOS, function onDumpDOS(s) { dbg.dumpDOS(s); });
this.fWinDbg = this.dbgAddrWinDbg = null;
this.cpu.addIntNotify(Interrupts.WINDBG.VECTOR, this, this.intWindowsDebugger);
if (Interrupts.WINDBGRM.ENABLED) {
this.fWinDbgRM = null;
this.cpu.addIntNotify(Interrupts.WINDBGRM.VECTOR, this, this.intWindowsDebuggerRM);
}
this.setReady();
};
/**
* intWindowsDebugger()
*
* @this {Debugger}
* @param {number} addr
* @return {boolean} true to proceed with the INT 0x41 software interrupt, false to skip
*/
Debugger.prototype.intWindowsDebugger = function(addr)
{
if (this.fWinDbg === false) return true;
var seg, limit;
var cpu = this.cpu;
var AX = cpu.regEAX & 0xffff;
var BX = cpu.regEBX & 0xffff;
var CX = cpu.regECX & 0xffff;
var DX = cpu.regEDX & 0xffff;
var SI = cpu.regESI & 0xffff;
var DI = cpu.regEDI & 0xffff;
var ES = cpu.segES.sel;
if (!this.fWinDbg) {
if (AX == Interrupts.WINDBG.IS_LOADED) {
/*
* We're only going to respond to this function if no one else did, in which case,
* we'll set fWinDbg to true and handle additional notifications.
*/
cpu.addIntReturn(addr, function(dbg) {
return function onInt41Return(nLevel) {
if ((cpu.regEAX & 0xffff) != Interrupts.WINDBG.LOADED) {
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBG.LOADED;
dbg.println("INT 0x41 processing enabled");
dbg.dbgAddrWinDbg = dbg.newAddr();
dbg.fWinDbg = true;
} else {
dbg.println("INT 0x41 processing disabled");
dbg.fWinDbg = false;
}
};
}(this));
}
return true;
}
switch(AX) {
case Interrupts.WINDBG.IS_LOADED:
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBG.LOADED;
break;
case Interrupts.WINDBG.LOAD_SEG:
/*
* The output should completely mimic WDEB386....
*/
limit = (seg = this.getSegment(CX))? seg.limit : 0;
this.println(this.getSZ(this.setAddr(this.dbgAddrWinDbg, DI, ES)) + "!undefined " + ((SI & 0x1)? "data" : "code") + '(' + str.toHex(BX+1, 4) + ")=#" + str.toHex(CX, 4) + " len " + str.toHex(limit+1));
break;
default:
this.println("INT 0x41: " + str.toHexWord(AX));
break;
}
return true;
};
if (Interrupts.WINDBGRM.ENABLED) {
/**
* intWindowsDebuggerRM()
*
* @this {Debugger}
* @param {number} addr
* @return {boolean} true to proceed with the INT 0x68 software interrupt, false to skip
*/
Debugger.prototype.intWindowsDebuggerRM = function(addr)
{
if (this.fWinDbgRM === false) return true;
var cpu = this.cpu;
var AH = this.cpu.regEAX & 0xff;
if (!this.fWinDbgRM) {
if (AH == Interrupts.WINDBGRM.IS_LOADED) {
/*
* We're only going to respond to this function if no one else did, in which case,
* we'll set fWinDbgRM to true and handle additional notifications.
*/
cpu.addIntReturn(addr, function(dbg) {
return function onInt68Return(nLevel) {
if ((cpu.regEAX & 0xffff) != Interrupts.WINDBGRM.LOADED) {
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBGRM.LOADED;
dbg.println("INT 0x68 processing enabled");
dbg.fWinDbgRM = true;
} else {
dbg.println("INT 0x68 processing disabled");
dbg.fWinDbgRM = false;
}
};
}(this));
}
return true;
}
switch(AH) {
case Interrupts.WINDBGRM.IS_LOADED:
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBGRM.LOADED;
break;
default:
this.println("INT 0x68: " + str.toHexByte(AH));
break;
}
return true;
};
}
/**
* setBinding(sHTMLType, sBinding, control)
*
@ -1575,10 +1699,32 @@ if (DEBUGGER) {
*/
Debugger.prototype.newAddr = function(off, sel, addr, fProt, fData32, fAddr32)
{
if (fProt === undefined) fProt = this.getProtMode();
if (fData32 === undefined) fData32 = (this.cpu && this.cpu.segCS.sizeData == 4);
if (fAddr32 === undefined) fAddr32 = (this.cpu && this.cpu.segCS.sizeAddr == 4);
return {off: off || 0, sel: sel, addr: addr, fProt: fProt || false, fTempBreak: false, fData32: fData32 || false, fAddr32: fAddr32 || false};
return this.setAddr({}, off, sel, addr, fProt, fData32, fAddr32);
};
/**
* setAddr(dbgAddr, off, sel, addr, fProt, fData32, fAddr32)
*
* @this {Debugger}
* @param {DbgAddr} dbgAddr
* @param {number|null|undefined} [off] (default is zero)
* @param {number|null|undefined} [sel] (default is undefined)
* @param {number|null|undefined} [addr] (default is undefined)
* @param {boolean} [fProt] (default is the current CPU mode)
* @param {boolean} [fData32] (default is the current CPU operand size)
* @param {boolean} [fAddr32] (default is the current CPU address size)
* @return {DbgAddr}
*/
Debugger.prototype.setAddr = function(dbgAddr, off, sel, addr, fProt, fData32, fAddr32)
{
dbgAddr.off = off || 0;
dbgAddr.sel = sel;
dbgAddr.addr = addr;
dbgAddr.fProt = (fProt == null)? this.getProtMode() : fProt;
dbgAddr.fData32 = (fData32 == null)? (this.cpu && this.cpu.segCS.sizeData == 4) : fData32;
dbgAddr.fAddr32 = (fAddr32 == null)? (this.cpu && this.cpu.segCS.sizeAddr == 4) : fAddr32;
dbgAddr.fTempBreak = false;
return dbgAddr;
};
/**
@ -1694,8 +1840,8 @@ if (DEBUGGER) {
cchMax = cchMax || 256;
while (s.length < cchMax) {
var b = this.getByte(dbgAddr, 1);
if (!b || b == 0x24) break;
s += (b >= 32 && b < 128? String.fromCharCode(b) : '.');
if (!b || b == 0x24 || b >= 127) break;
s += (b >= 32? String.fromCharCode(b) : '.');
}
return s;
};
@ -2853,7 +2999,7 @@ if (DEBUGGER) {
* powerDown(fSave, fShutdown)
*
* @this {Debugger}
* @param {boolean} fSave
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean}
*/
@ -3704,8 +3850,8 @@ if (DEBUGGER) {
sOperands += (sOperand || "???");
}
var sLine = this.hexAddr(dbgAddrIns) + ' ';
var sBytes = "";
var sLine = this.hexAddr(dbgAddrIns) + ' ';
if (dbgAddrIns.addr != X86.ADDR_INVALID && dbgAddr.addr != X86.ADDR_INVALID) {
do {
sBytes += str.toHex(this.getByte(dbgAddrIns, 1), 2);
@ -5078,7 +5224,23 @@ if (DEBUGGER) {
}
if (sAddr == "state") {
this.println(this.cmp.powerOff(true));
var s = this.cmp.powerOff(true);
if (sLen == "console") {
/*
* Console buffers are notoriously small, and even the following code, which breaks the
* data into parts (eg, "d state console 1", "d state console 2", etc) just isn't that helpful.
*
* var nPart = +sBytes;
* if (nPart) s = s.substr(1000000 * (nPart-1), 1000000);
*
* So, the best way to capture a large machine state is to run your own local server and use
* server-side storage. Take a look at the "Save" binding in computer.js, which binds an HTML
* control to the computer.powerOff() and computer.saveServerState() functions.
*/
console.log(s);
} else {
this.println(s);
}
return;
}
@ -5803,12 +5965,13 @@ if (DEBUGGER) {
};
/**
* doRegisters(asArgs)
* doRegisters(asArgs, fInstruction)
*
* @this {Debugger}
* @param {Array.<string>} [asArgs]
* @param {boolean} [fInstruction] (default is true)
*/
Debugger.prototype.doRegisters = function(asArgs)
Debugger.prototype.doRegisters = function(asArgs, fInstruction)
{
if (asArgs && asArgs[1] == '?') {
this.println("register commands:");
@ -5817,13 +5980,16 @@ if (DEBUGGER) {
this.println("\trx [#]\tset flag or register x to [#]");
return;
}
var fIns = true, fProt;
var fProt;
if (fInstruction == null) fInstruction = true;
if (asArgs != null && asArgs.length > 1) {
var sReg = asArgs[1];
if (sReg == 'p') {
fProt = (this.cpu.model >= X86.MODEL_80286);
} else {
// fIns = false;
// fInstruction = false;
var sValue = null;
var i = sReg.indexOf('=');
if (i > 0) {
@ -5909,13 +6075,13 @@ if (DEBUGGER) {
this.cpu.setSS(w);
break;
case "CS":
// fIns = true;
// fInstruction = true;
this.cpu.setCS(w);
this.dbgAddrNextCode = this.newAddr(this.cpu.getIP(), this.cpu.getCS());
break;
case "IP":
case "EIP":
// fIns = true;
// fInstruction = true;
this.cpu.setIP(w);
this.dbgAddrNextCode = this.newAddr(this.cpu.getIP(), this.cpu.getCS());
break;
@ -6052,7 +6218,7 @@ if (DEBUGGER) {
this.println(this.getRegDump(fProt));
if (fIns) {
if (fInstruction) {
this.dbgAddrNextCode = this.newAddr(this.cpu.getIP(), this.cpu.getCS());
this.doUnassemble(this.hexAddr(this.dbgAddrNextCode));
}

View file

@ -868,7 +868,7 @@ Disk.prototype.donePowerUp = function(drive, disk, sDiskName, sDiskPath)
* exist, and even after it was created, it didn't originally receive powerDown() notifications.
*
* @this {Disk}
* @param {boolean} fSave
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean}
*/

View file

@ -608,7 +608,7 @@ FDC.prototype.powerUp = function(data, fRepower)
* powerDown(fSave, fShutdown)
*
* @this {FDC}
* @param {boolean} fSave
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/

View file

@ -598,7 +598,7 @@ HDC.prototype.powerUp = function(data, fRepower)
* powerDown(fSave, fShutdown)
*
* @this {HDC}
* @param {boolean} fSave
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean}
*/

View file

@ -59,7 +59,19 @@ var Interrupts = {
DOS_IDLE: 0x28,
DOS_NETBIOS:0x2A,
MOUSE: 0x33,
FUNCS: {}
WINDBG: { // Windows Debugger (eg, WDEB386) protected-mode interface
VECTOR: 0x41,
IS_LOADED: 0x004F, // AX command
LOADED: 0xF386, // returned in AX if Windows Debugger loaded
LOAD_SEG: 0x0050 // SI==0 if code, 1 if data; BX==segnum-1; CX==selector; DX==data instance; ES:[E]DI->module name
},
WINDBGRM: { // Windows Debugger (eg, WDEB386) real-mode interface
VECTOR: 0x68,
IS_LOADED: 0x43, // AH command
LOADED: 0xF386, // returned in AX if Windows Debugger loaded
ENABLED: false // support for WINDBGRM interrupts is NOT enabled by default
},
FUNCS: {} // filled in only if DEBUGGER is true
};
if (DEBUGGER) {
@ -87,7 +99,7 @@ if (DEBUGGER) {
0x16: "get drive %DL change line status",
0x17: "set drive %DL DASD type",
0x18: "set drive %DL media type"
},
};
Interrupts.FUNCS[Interrupts.CASSETTE] = {
0x80: "open device",
0x81: "close device",
@ -197,6 +209,9 @@ if (DEBUGGER) {
0x63: "get lead byte table (%AL)", // DOS 2.25 and 3.20+
0x6C: "extended open file $%DS:%SI" // DOS 4.00+
};
Interrupts.FUNCS[Interrupts.WINDBG.VECTOR] = {
0x004F: "check debugger loaded" // WINDBG.IS_LOADED returns WINDBG.LOADED (0xF386) if debugger loaded
};
}
/*

View file

@ -1367,7 +1367,7 @@ Keyboard.prototype.powerUp = function(data, fRepower)
* powerDown(fSave, fShutdown)
*
* @this {Keyboard}
* @param {boolean} fSave
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/

View file

@ -288,7 +288,7 @@ Mouse.prototype.powerUp = function(data, fRepower)
* powerDown(fSave, fShutdown)
*
* @this {Mouse}
* @param {boolean} fSave
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/

View file

@ -369,7 +369,7 @@ Panel.prototype.powerUp = function(data, fRepower)
* powerDown(fSave, fShutdown)
*
* @this {Panel}
* @param {boolean} fSave
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/

View file

@ -119,7 +119,7 @@ RAM.prototype.powerUp = function(data, fRepower)
* powerDown(fSave, fShutdown)
*
* @this {RAM}
* @param {boolean} fSave
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/

View file

@ -202,7 +202,7 @@ ROM.prototype.powerUp = function(data, fRepower)
* created, above and beyond those symbols we automatically loaded, if any, along with the ROM).
*
* @this {ROM}
* @param {boolean} fSave
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/

View file

@ -421,7 +421,7 @@ SerialPort.prototype.powerUp = function(data, fRepower)
* powerDown(fSave, fShutdown)
*
* @this {SerialPort}
* @param {boolean} fSave
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/

View file

@ -3339,7 +3339,7 @@ Video.prototype.powerUp = function(data, fRepower)
* buffer contents, and blocking all further updates to the display.
*
* @this {Video}
* @param {boolean} fSave
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/

View file

@ -1605,6 +1605,9 @@ X86CPU.prototype.getChecksum = function()
*
* Add an software interrupt notification handler to the CPU's list of such handlers.
*
* TODO: Consider adding removeIntNotify(). Example use case: if the Debugger's intWindowsDebugger() function
* detects that an INT 0x41 client is loaded, it would be quite happy to uninstall itself.
*
* @this {X86CPU}
* @param {number} nInt
* @param {Component} component
@ -1645,10 +1648,12 @@ X86CPU.prototype.checkIntNotify = function(nInt)
* The enabling of INT messages is one of the criteria that's also included in the Debugger's checksEnabled()
* function, and therefore included in fDebugCheck, so for maximum speed, we check fDebugCheck first.
*
* NOTE: By wrapping this in MAXDEBUG, we're effectively eliminating the need for any checkIntReturn() calls;
* onIntReturn() generates a lot of noise, via dbg.messageIntReturn(), and because there's no way to be be sure
* we'll catch the return (or for some interrupts, *whether* they will return), it's safer to disable this
* feature unless you really want it.
* NOTE: We've added MAXDEBUG to the test below, because onIntReturn() generates a lot of noise, via
* dbg.messageIntReturn(), and because there's no way to be sure we'll catch the return (or for some interrupts,
* *whether* they will return), so it's safer to disable this feature unless you really want it.
*
* For most purposes, just having dbg.messageInt(), and the Debugger's ability to selectively turn categories
* of messages on and off, is good enough.
*/
if (DEBUGGER && this.aFlags.fDebugCheck) {
if (this.messageEnabled(Messages.INT) && this.dbg.messageInt(nInt, this.regLIP) && MAXDEBUG) {

View file

@ -1325,7 +1325,7 @@ X86.fnIRET = function IRET()
if (this.setCSIP(newIP, newCS, false) != null) {
this.setPS(newPS, cpl);
if (MAXDEBUG && this.cIntReturn) this.checkIntReturn(this.regLIP);
if (this.cIntReturn) this.checkIntReturn(this.regLIP);
}
}
this.opLSP = X86.ADDR_INVALID;
@ -2280,7 +2280,7 @@ X86.fnRETF = function RETF(n)
this.zeroSeg(this.segGS);
}
}
if (MAXDEBUG && n == 2 && this.cIntReturn) this.checkIntReturn(this.regLIP);
if (n == 2 && this.cIntReturn) this.checkIntReturn(this.regLIP);
this.opLSP = X86.ADDR_INVALID;
};
@ -3376,6 +3376,7 @@ X86.fnVERR = function VERR(dst, src)
}
}
this.clearZF();
if (this.sizeData > 2 || this.sizeAddr > 2) this.stopCPU();
return dst;
};
@ -3413,6 +3414,7 @@ X86.fnVERW = function VERW(dst, src)
}
}
this.clearZF();
if (this.sizeData > 2 || this.sizeAddr > 2) this.stopCPU();
return dst;
};

View file

@ -3486,6 +3486,10 @@ X86.opINTn = function INTn()
return;
}
var nInt = this.getIPByte();
/*
* checkIntNotify() checks for any notification handlers registered via addIntNotify(), calls them,
* and returns false ONLY if a notification handler returned false (ie, requesting the interrupt be skipped).
*/
if (this.checkIntNotify(nInt)) {
X86.fnINT.call(this, nInt, null, 0);
return;

View file

@ -102,8 +102,18 @@ if (fLogging) {
HTMLOut.setOptions({'logfile': streamLog});
app.use(express.logger({ format: 'default', stream: streamLog }));
}
app.use(express.json({limit: '4mb'}));
app.use(express.urlencoded({limit: '4mb'}));
/*
* To be able to save states for machines with large states, I have to rely on server-side
* state API support (see processUserAPI() in httpapi.js in the HTMLOut module), because there
* don't seem to be any good client-side solutions (localStorage is notoriously limited, and
* "data:" URLs crash the browser if they're too large). However, I don't want to jack up the
* server upload limits too high on a "production" server, so I set a higher limit only for
* "debug" servers).
*/
app.use(express.json({limit: fDebug? '128mb' : '4mb'}));
app.use(express.urlencoded({limit: fDebug? '128mb' : '4mb'}));
app.use(HTMLOut.filter);
app.use(express.compress());