Debugger improvements for DOS debugging
This commit is contained in:
parent
4e69520a5b
commit
ebf6933536
3 changed files with 334 additions and 293 deletions
|
|
@ -4087,9 +4087,9 @@ ChipSet.prototype.set8042OutPort = function(b)
|
||||||
/**
|
/**
|
||||||
* notifyKbdData(fAvail)
|
* notifyKbdData(fAvail)
|
||||||
*
|
*
|
||||||
* Previously, the Keyboard would simply call setIRR() when it had some data for the keyboard controller.
|
* In the old days of PCjs, the Keyboard component would simply call setIRR() when it had some data for the
|
||||||
* Now the interface is a little more nuanced, giving the ChipSet/8042 the opportunity to decide when to
|
* keyboard controller. However, that was completely inappropriate. The sole responsibility of the Keyboard
|
||||||
* raise IRQ.KBD.
|
* is to emulate an actual keyboard and notify us whenever it has some data; it doesn't mess with IRQ lines.
|
||||||
*
|
*
|
||||||
* If there's an 8042, we check (this.b8042CmdData & ChipSet.KBC.DATA.CMD.NO_CLOCK); if NO_CLOCK is clear,
|
* If there's an 8042, we check (this.b8042CmdData & ChipSet.KBC.DATA.CMD.NO_CLOCK); if NO_CLOCK is clear,
|
||||||
* we can raise the IRQ immediately. Well, not quite immediately....
|
* we can raise the IRQ immediately. Well, not quite immediately....
|
||||||
|
|
@ -4166,7 +4166,7 @@ ChipSet.prototype.notifyKbdData = function(fAvail)
|
||||||
{
|
{
|
||||||
if (this.model < ChipSet.MODEL_5170) {
|
if (this.model < ChipSet.MODEL_5170) {
|
||||||
/*
|
/*
|
||||||
* TODO: Should we be checking bPPI for PPI_B.CLK_KBD on these older machines, before called setIRR()?
|
* TODO: Should we be checking bPPI for PPI_B.CLK_KBD on these older machines, before calling setIRR()?
|
||||||
*/
|
*/
|
||||||
this.setIRR(ChipSet.IRQ.KBD, 4);
|
this.setIRR(ChipSet.IRQ.KBD, 4);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1171,7 +1171,9 @@ if (DEBUGGER) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cpu.addIntNotify(Debugger.INT_DOS, this, this.intDOSCall);
|
this.messageDump(Debugger.MESSAGE_DOS, function onDumpDOS(s) {
|
||||||
|
dbg.dumpDOS(s);
|
||||||
|
});
|
||||||
|
|
||||||
this.setReady();
|
this.setReady();
|
||||||
|
|
||||||
|
|
@ -1281,6 +1283,56 @@ if (DEBUGGER) {
|
||||||
if (this.controlDebug) this.controlDebug.focus();
|
if (this.controlDebug) this.controlDebug.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dumpDOS(s)
|
||||||
|
*
|
||||||
|
* @this {Debugger}
|
||||||
|
* @param {string} [s]
|
||||||
|
*/
|
||||||
|
Debugger.prototype.dumpDOS = function(s)
|
||||||
|
{
|
||||||
|
if (!s) return;
|
||||||
|
|
||||||
|
this.println("dumpDOS(" + s + ")");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If s is provided and str.parseInt(s) succeeds, then we assume it represents a starting
|
||||||
|
* MCB (Memory Control Block) segment, and we dump the corresponding blocks.
|
||||||
|
*/
|
||||||
|
var seg = str.parseInt(s);
|
||||||
|
while (seg) {
|
||||||
|
var aAddr = this.newAddr(0, seg);
|
||||||
|
var bSig = this.getByte(aAddr, 1);
|
||||||
|
var wPID = this.getWord(aAddr, 2);
|
||||||
|
var wParas = this.getWord(aAddr, 5);
|
||||||
|
if (bSig != 0x4D && bSig != 0x5A) break;
|
||||||
|
this.println(str.toHexAddr(0, seg) + ": '" + String.fromCharCode(bSig) + "' PID=" + str.toHexWord(wPID) + " LEN=" + str.toHexWord(wParas) + ' "' + this.dumpSZ(aAddr, 8) + '"');
|
||||||
|
seg += 1 + wParas;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dumpSZ(aAddr, cchMax)
|
||||||
|
*
|
||||||
|
* Dump helper for zero-terminated strings.
|
||||||
|
*
|
||||||
|
* @this {Debugger}
|
||||||
|
* @param {Array} aAddr
|
||||||
|
* @param {number} [cchMax]
|
||||||
|
* @return {string} (and aAddr advanced past the terminating zero)
|
||||||
|
*/
|
||||||
|
Debugger.prototype.dumpSZ = function(aAddr, cchMax)
|
||||||
|
{
|
||||||
|
var sChars = "";
|
||||||
|
cchMax = cchMax || 256;
|
||||||
|
while (sChars.length < cchMax) {
|
||||||
|
var b = this.getByte(aAddr, 1);
|
||||||
|
if (!b) break;
|
||||||
|
sChars += (b >= 32 && b < 128? String.fromCharCode(b) : ".");
|
||||||
|
}
|
||||||
|
return sChars;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* initMessages(sEnable)
|
* initMessages(sEnable)
|
||||||
*
|
*
|
||||||
|
|
@ -1373,14 +1425,21 @@ if (DEBUGGER) {
|
||||||
* @this {Debugger}
|
* @this {Debugger}
|
||||||
* @param {number} nInt
|
* @param {number} nInt
|
||||||
* @param {number} addr
|
* @param {number} addr
|
||||||
|
* @return {boolean} true if message generated, false if not
|
||||||
*/
|
*/
|
||||||
Debugger.prototype.messageInt = function(nInt, addr)
|
Debugger.prototype.messageInt = function(nInt, addr)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* TODO: Filtering of interrupt numbers below should be user-definable; this is very quick-and-dirty.
|
* TODO: Filtering of interrupt numbers below should be user-definable; this is very quick-and-dirty.
|
||||||
*/
|
*/
|
||||||
if (nInt != 0x10 && nInt != 0x15 && nInt != 0x16 && nInt != 0x1A && nInt != 0x1C) {
|
var fMessage = false;
|
||||||
var AH = this.cpu.regAX >> 8;
|
var AH = this.cpu.regAX >> 8;
|
||||||
|
if (this.messageEnabled(Debugger.MESSAGE_DOS)) {
|
||||||
|
fMessage = (nInt == 0x21 && AH != 0x0b);
|
||||||
|
} else {
|
||||||
|
fMessage = (nInt != 0x10 && nInt != 0x15 && nInt != 0x16 && nInt != 0x1A && nInt != 0x1C);
|
||||||
|
}
|
||||||
|
if (fMessage) {
|
||||||
var aFuncs = Debugger.INT_FUNCS[nInt];
|
var aFuncs = Debugger.INT_FUNCS[nInt];
|
||||||
var sFunc = (aFuncs && aFuncs[AH]) || "";
|
var sFunc = (aFuncs && aFuncs[AH]) || "";
|
||||||
if (sFunc) {
|
if (sFunc) {
|
||||||
|
|
@ -1389,6 +1448,7 @@ if (DEBUGGER) {
|
||||||
}
|
}
|
||||||
this.message("INT 0x" + str.toHexByte(nInt) + ": AH=" + str.toHexByte(AH) + " at " + str.toHexAddr(addr - this.cpu.segCS.base, this.cpu.segCS.sel) + sFunc);
|
this.message("INT 0x" + str.toHexByte(nInt) + ": AH=" + str.toHexByte(AH) + " at " + str.toHexAddr(addr - this.cpu.segCS.base, this.cpu.segCS.sel) + sFunc);
|
||||||
}
|
}
|
||||||
|
return fMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1402,12 +1462,7 @@ if (DEBUGGER) {
|
||||||
*/
|
*/
|
||||||
Debugger.prototype.messageIntReturn = function(nInt, nLevel, nCycles, sResult)
|
Debugger.prototype.messageIntReturn = function(nInt, nLevel, nCycles, sResult)
|
||||||
{
|
{
|
||||||
/*
|
this.message("INT 0x" + str.toHexByte(nInt) + ": C=" + (this.cpu.getCF()? 1 : 0) + (sResult || "") + " (cycles=" + nCycles + (nLevel? ",level=" + (nLevel+1) : "") + ")");
|
||||||
* TODO: Filtering of interrupt numbers below should be user-definable; this is very quick-and-dirty.
|
|
||||||
*/
|
|
||||||
if (nInt < 0x20 && nInt != 0x10 && nInt != 0x15 && nInt != 0x16 && nInt != 0x1A && nInt != 0x1C) {
|
|
||||||
this.message("INT 0x" + str.toHexByte(nInt) + "(" + nLevel + "): C=" + (this.cpu.getCF()? 1 : 0) + (sResult || "") + " (cycles=" + nCycles + ")");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1538,19 +1593,6 @@ if (DEBUGGER) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* intDOSCall(addr)
|
|
||||||
*
|
|
||||||
* @this {Debugger}
|
|
||||||
* @param {number} addr
|
|
||||||
* @return {boolean} true to proceed with the INT 0x21 software interrupt, false to skip (but we NEVER skip)
|
|
||||||
*/
|
|
||||||
Debugger.prototype.intDOSCall = function(addr)
|
|
||||||
{
|
|
||||||
if (this.messageEnabled(Debugger.MESSAGE_DOS | Debugger.MESSAGE_INT)) this.messageInt(Debugger.INT_DOS, addr);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* init()
|
* init()
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -924,11 +924,10 @@ X86CPU.prototype.checkIntNotify = function(nInt)
|
||||||
}
|
}
|
||||||
else if (DEBUGGER && this.aFlags.fDebugCheck) {
|
else if (DEBUGGER && this.aFlags.fDebugCheck) {
|
||||||
/*
|
/*
|
||||||
* Enabling MESSAGE_INT messages is one of the criteria that's also included in fDebugCheck, so for maximum
|
* Enabling MESSAGE_INT messages is one of the criteria that's also included in fDebugCheck,
|
||||||
* speed, we check fDebugCheck first.
|
* so for maximum speed, we check fDebugCheck first.
|
||||||
*/
|
*/
|
||||||
if (this.dbg.messageEnabled(Debugger.MESSAGE_INT)) {
|
if (this.dbg.messageEnabled(Debugger.MESSAGE_INT) && this.dbg.messageInt(nInt, this.regEIP)) {
|
||||||
this.dbg.messageInt(nInt, this.regEIP);
|
|
||||||
this.addIntReturn(this.regEIP, function(cpu, nCycles) {
|
this.addIntReturn(this.regEIP, function(cpu, nCycles) {
|
||||||
return function onIntReturn(nLevel) {
|
return function onIntReturn(nLevel) {
|
||||||
cpu.dbg.messageIntReturn(nInt, nLevel, cpu.getCycles() - nCycles);
|
cpu.dbg.messageIntReturn(nInt, nLevel, cpu.getCycles() - nCycles);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue