More 80386 support, and an audio API change forced by Chrome
This commit is contained in:
parent
5b99b51c64
commit
d3d431eb2c
9 changed files with 2406 additions and 2358 deletions
|
|
@ -4789,15 +4789,15 @@ ChipSet.prototype.setSpeaker = function(fOn)
|
|||
if (this.messageEnabled(Messages.SPEAKER)) this.printMessage("speaker set to " + freq + "hz", true);
|
||||
} else {
|
||||
this.sourceAudio = this.contextAudio['createOscillator']();
|
||||
this.sourceAudio['type'] = 1; // 0: sine wave, 1: square wave, 2: sawtooth wave, 3: triangle wave
|
||||
this.sourceAudio['type'] = "square"; // any of: "sine", "square", "sawtooth", "triangle", "custom"
|
||||
this.sourceAudio['connect'](this.contextAudio['destination']);
|
||||
this.sourceAudio['frequency']['value'] = freq;
|
||||
if (this.messageEnabled(Messages.SPEAKER)) this.printMessage("speaker on at " + freq + "hz", true);
|
||||
this.sourceAudio['noteOn'](0); // aka start()
|
||||
this.sourceAudio['start'](0);
|
||||
}
|
||||
} else {
|
||||
if (this.sourceAudio) {
|
||||
this.sourceAudio['noteOff'](0); // aka stop()
|
||||
this.sourceAudio['stop'](0);
|
||||
this.sourceAudio['disconnect'](); // QUESTION: is this automatic following a stop(), since this particular source cannot be started again?
|
||||
delete this.sourceAudio; // QUESTION: ditto?
|
||||
if (this.messageEnabled(Messages.SPEAKER)) this.printMessage("speaker off at " + freq + "hz", true);
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ if (DEBUGGER) {
|
|||
|
||||
Debugger.RMS = [
|
||||
"BX+SI", "BX+DI", "BP+SI", "BP+DI", "SI", "DI", "BP", "BX",
|
||||
"EAX", "ECX", "EDX", "EBX", "[SIB]", "EBP", "ESI", "EDI"
|
||||
"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"
|
||||
];
|
||||
|
||||
/*
|
||||
|
|
@ -2506,7 +2506,7 @@ if (DEBUGGER) {
|
|||
* @this {Debugger}
|
||||
* @param {Array} aAddr
|
||||
* @param {boolean} [fWrite]
|
||||
* @param {number} [cb] is number of extra bytes to check (0 or 1)
|
||||
* @param {number} [cb] is number of extra bytes to check (0, 1 or 3)
|
||||
* @return {number} is the corresponding physical address, or X86.ADDR_INVALID
|
||||
*/
|
||||
Debugger.prototype.getAddr = function(aAddr, fWrite, cb)
|
||||
|
|
@ -2983,7 +2983,7 @@ if (DEBUGGER) {
|
|||
}
|
||||
|
||||
if (sComment) {
|
||||
sLine = str.pad(sLine, 50) + ';' + sComment;
|
||||
sLine = str.pad(sLine, 52) + ';' + sComment;
|
||||
if (!this.cpu.aFlags.fChecksum) {
|
||||
sLine += (nSequence != null? '=' + nSequence.toString() : "");
|
||||
} else {
|
||||
|
|
@ -3044,7 +3044,7 @@ if (DEBUGGER) {
|
|||
* @this {Debugger}
|
||||
* @param {number} bReg
|
||||
* @param {number} type
|
||||
* @param {Array} aAddr
|
||||
* @param {Array} aAddr (aAddr[4] is true if 32-bit operands, aAddr[5] is true if 32-bit addressing)
|
||||
* @return {string} operand
|
||||
*/
|
||||
Debugger.prototype.getRegOperand = function(bReg, type, aAddr)
|
||||
|
|
@ -3072,13 +3072,39 @@ if (DEBUGGER) {
|
|||
return Debugger.REGS[bReg];
|
||||
};
|
||||
|
||||
/**
|
||||
* getSIBOperand(bMod, aAddr)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} bMod
|
||||
* @param {Array} aAddr (aAddr[4] is true if 32-bit operands, aAddr[5] is true if 32-bit addressing)
|
||||
* @return {string} operand
|
||||
*/
|
||||
Debugger.prototype.getSIBOperand = function(bMod, aAddr)
|
||||
{
|
||||
var bSIB = this.getByte(aAddr, 1);
|
||||
var bScale = bSIB >> 6;
|
||||
var bIndex = (bSIB >> 3) & 0x7;
|
||||
var bBase = bSIB & 0x7;
|
||||
var sOperand = "";
|
||||
if (bMod || bBase != 5) {
|
||||
sOperand = Debugger.RMS[bBase + 8];
|
||||
}
|
||||
if (bIndex != 4) {
|
||||
if (sOperand) sOperand += '+';
|
||||
sOperand += Debugger.RMS[bIndex + 8];
|
||||
if (bScale) sOperand += '*' + (0x1 << bScale);
|
||||
}
|
||||
return sOperand;
|
||||
};
|
||||
|
||||
/**
|
||||
* getModRMOperand(bModRM, type, aAddr)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} bModRM
|
||||
* @param {number} type
|
||||
* @param {Array} aAddr
|
||||
* @param {Array} aAddr (aAddr[4] is true if 32-bit operands, aAddr[5] is true if 32-bit addressing)
|
||||
* @return {string} operand
|
||||
*/
|
||||
Debugger.prototype.getModRMOperand = function(bModRM, type, aAddr)
|
||||
|
|
@ -3088,33 +3114,42 @@ if (DEBUGGER) {
|
|||
var bRM = bModRM & 0x7;
|
||||
if (bMod < 3) {
|
||||
var disp;
|
||||
if (!bMod && bRM == 6) {
|
||||
disp = this.getShort(aAddr, 2);
|
||||
sOperand = str.toHexWord(disp);
|
||||
}
|
||||
else {
|
||||
if (aAddr[5]) bRM += 8;
|
||||
sOperand = Debugger.RMS[bRM];
|
||||
if (bMod == 1) {
|
||||
disp = this.getByte(aAddr, 1);
|
||||
if (!(disp & 0x80)) {
|
||||
sOperand += "+" + str.toHexByte(disp);
|
||||
}
|
||||
else {
|
||||
disp = ((disp << 24) >> 24);
|
||||
sOperand += "-" + str.toHexByte(-disp);
|
||||
if (!bMod && (!aAddr[5] && bRM == 6 || aAddr[5] && bRM == 5)) {
|
||||
bMod = 2;
|
||||
} else {
|
||||
if (aAddr[5]) {
|
||||
if (bRM != 4) {
|
||||
bRM += 8;
|
||||
} else {
|
||||
sOperand = this.getSIBOperand(bMod, aAddr);
|
||||
}
|
||||
}
|
||||
else if (bMod == 2) {
|
||||
if (!sOperand) sOperand = Debugger.RMS[bRM];
|
||||
}
|
||||
if (bMod == 1) {
|
||||
disp = this.getByte(aAddr, 1);
|
||||
if (!(disp & 0x80)) {
|
||||
sOperand += "+" + str.toHexByte(disp);
|
||||
}
|
||||
else {
|
||||
disp = ((disp << 24) >> 24);
|
||||
sOperand += "-" + str.toHexByte(-disp);
|
||||
}
|
||||
}
|
||||
else if (bMod == 2) {
|
||||
if (sOperand) sOperand += '+';
|
||||
if (!aAddr[5]) {
|
||||
disp = this.getShort(aAddr, 2);
|
||||
sOperand += "+" + str.toHexWord(disp);
|
||||
sOperand += str.toHexWord(disp);
|
||||
} else {
|
||||
disp = this.getLong(aAddr, 4);
|
||||
sOperand += str.toHex(disp);
|
||||
}
|
||||
}
|
||||
sOperand = "[" + sOperand + "]";
|
||||
}
|
||||
else {
|
||||
sOperand = this.getRegOperand(bRM, type, aAddr);
|
||||
// sOperand = Debugger.REGS[bRM + ((type & Debugger.TYPE_SIZE) == Debugger.TYPE_BYTE? 0 : 8)];
|
||||
}
|
||||
return sOperand;
|
||||
};
|
||||
|
|
@ -3744,7 +3779,6 @@ if (DEBUGGER) {
|
|||
var aOpBytes = this.parseInstruction(asArgs[2], asArgs[3], aAddr);
|
||||
if (aOpBytes.length) {
|
||||
for (var i = 0; i < aOpBytes.length; i++) {
|
||||
// this.println(this.hexAddr(aAddr) + ": " + str.toHexByte(aOpBytes[i]));
|
||||
this.setByte(aAddr, aOpBytes[i], 1);
|
||||
}
|
||||
/*
|
||||
|
|
@ -4946,8 +4980,8 @@ if (DEBUGGER) {
|
|||
* aAddr[5] to true whenever the address size is 32-bit. Initially, both fields must be set to match
|
||||
* the size of the current code segment.
|
||||
*/
|
||||
aAddr[4] = (this.cpu.segCS.dataSize == 4);
|
||||
aAddr[5] = (this.cpu.segCS.addrSize == 4);
|
||||
aAddr[4] = (this.cpu.dataSize == 4);
|
||||
aAddr[5] = (this.cpu.addrSize == 4);
|
||||
fInitSize = false;
|
||||
}
|
||||
if (this.isPrefixIns(bOpcode)) {
|
||||
|
|
|
|||
|
|
@ -253,12 +253,14 @@ var X86 = {
|
|||
NOREAD: 0x0001,
|
||||
NOWRITE: 0x0002,
|
||||
NOINTR: 0x0004, // indicates a segreg has been set, or a prefix, or an STI (delay INTR acknowledgement)
|
||||
SEG: 0x0010,
|
||||
LOCK: 0x0020,
|
||||
SEG: 0x0010, // segment override
|
||||
LOCK: 0x0020, // lock prefix
|
||||
REPZ: 0x0040, // repeat while Z (NOTE: this value MUST match PS.ZF; see opCMPSb/opCMPSw/opSCASb/opSCASw)
|
||||
REPNZ: 0x0080, // repeat while NZ
|
||||
REPEAT: 0x0100, // this indicates that an instruction is being repeated (ie, some iteration AFTER the first)
|
||||
PUSHSP: 0x0200 // the SP register is potentially being referenced by a PUSH SP opcode, adjustment may be required
|
||||
REPEAT: 0x0100, // indicates that an instruction is being repeated (ie, some iteration AFTER the first)
|
||||
PUSHSP: 0x0200, // the SP register is potentially being referenced by a PUSH SP opcode, adjustment may be required
|
||||
DATASIZE: 0x1000, // data size override
|
||||
ADDRSIZE: 0x2000 // address size override
|
||||
},
|
||||
/*
|
||||
* Bit values for intFlags
|
||||
|
|
@ -375,6 +377,6 @@ X86.PS.SAHF = (X86.PS.CF | X86.PS.PF | X86.PS.AF | X86.PS.ZF | X86.PS.SF);
|
|||
* into opPrefixes; otherwise, opPrefixes is zeroed as well. This gives prefix-conscious instructions like LODS, MOVS,
|
||||
* STOS, CMPS, etc, a way of determining which prefixes, if any, immediately preceded them.
|
||||
*/
|
||||
X86.OPFLAG.PREFIXES = (X86.OPFLAG.SEG | X86.OPFLAG.LOCK | X86.OPFLAG.REPZ | X86.OPFLAG.REPNZ);
|
||||
X86.OPFLAG.PREFIXES = (X86.OPFLAG.SEG | X86.OPFLAG.LOCK | X86.OPFLAG.REPZ | X86.OPFLAG.REPNZ | X86.OPFLAG.DATASIZE | X86.OPFLAG.ADDRSIZE);
|
||||
|
||||
if (typeof module !== 'undefined') module.exports = X86;
|
||||
|
|
|
|||
|
|
@ -942,7 +942,7 @@ X86CPU.prototype.resetRegs = function()
|
|||
|
||||
this.setCSIP(0, 0xffff); // this should be called before the first setPS() call
|
||||
|
||||
if (!I386) this.setSizes();
|
||||
if (!I386) this.resetSizes();
|
||||
|
||||
if (BACKTRACK) {
|
||||
/*
|
||||
|
|
@ -1073,11 +1073,11 @@ X86CPU.prototype.setDataSize = function()
|
|||
};
|
||||
|
||||
/**
|
||||
* setSizes()
|
||||
* resetSizes()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86CPU.prototype.setSizes = function()
|
||||
X86CPU.prototype.resetSizes = function()
|
||||
{
|
||||
/*
|
||||
* The following contain the (default) ADDRESS size (2 for 16 bits, 4 for 32 bits), and the corresponding
|
||||
|
|
@ -1109,6 +1109,8 @@ X86CPU.prototype.setSizes = function()
|
|||
this.dataMask = this.segCS.dataMask;
|
||||
|
||||
this.setDataSize();
|
||||
|
||||
this.opPrefixes &= ~(X86.OPFLAG.ADDRSIZE | X86.OPFLAG.DATASIZE);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1441,7 +1443,7 @@ X86CPU.prototype.setCS = function(sel)
|
|||
var regEIP = this.getIP();
|
||||
this.regLIP = this.segCS.load(sel) + regEIP;
|
||||
this.regLIPLimit = this.segCS.base + this.segCS.limit;
|
||||
if (I386) this.setSizes();
|
||||
if (I386) this.resetSizes();
|
||||
if (!BUGS_8086) this.opFlags |= this.OPFLAG_NOINTR8086;
|
||||
if (PREFETCH) this.flushPrefetch(this.regLIP);
|
||||
};
|
||||
|
|
@ -1641,7 +1643,7 @@ X86CPU.prototype.setCSIP = function(off, sel, fCall)
|
|||
if (base != X86.ADDR_INVALID) {
|
||||
this.regLIP = base + this.regEIP;
|
||||
this.regLIPLimit = base + this.segCS.limit;
|
||||
if (I386) this.setSizes();
|
||||
if (I386) this.resetSizes();
|
||||
if (PREFETCH) this.flushPrefetch(this.regLIP);
|
||||
return this.segCS.fStackSwitch;
|
||||
}
|
||||
|
|
@ -3196,17 +3198,25 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
|
|||
* NOTE: The way we restart string instructions actually fixes an 8086/8088 flaw, because string
|
||||
* instructions with multiple prefixes (eg, a REP and a segment override) would not be restarted
|
||||
* properly following a hardware interrupt. The recommended workarounds were to either turn off
|
||||
* interrupts or make sure the REP prefix was first and follow the string instruction with a LOOPNZ
|
||||
* back to the REP. To emulate this flawed behavior, turn on BUGS_8086.
|
||||
* interrupts or to follow the string instruction with a LOOPNZ back to the first prefix byte.
|
||||
* To emulate this flawed behavior, turn on BUGS_8086.
|
||||
*/
|
||||
this.opLIP = this.regLIP;
|
||||
this.segData = this.segDS;
|
||||
this.segStack = this.segSS;
|
||||
this.regEA = this.regEAWrite = X86.ADDR_INVALID;
|
||||
|
||||
if (I386) this.setSizes();
|
||||
if (I386 && (this.opPrefixes & (X86.OPFLAG.ADDRSIZE | X86.OPFLAG.DATASIZE))) {
|
||||
this.resetSizes();
|
||||
if (DEBUG && DEBUGGER) {
|
||||
this.println("80386 override processed");
|
||||
this.stopCPU();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.opPrefixes = this.opFlags & X86.OPFLAG.REPEAT;
|
||||
|
||||
if (this.intFlags) {
|
||||
if (this.checkINTR()) {
|
||||
if (!nMinCycles) {
|
||||
|
|
|
|||
|
|
@ -1609,12 +1609,11 @@ X86.opGS = function GS()
|
|||
X86.opOS = function OS()
|
||||
{
|
||||
if (I386) {
|
||||
this.opFlags |= X86.OPFLAG.SEG;
|
||||
this.opFlags |= X86.OPFLAG.DATASIZE;
|
||||
this.dataSize ^= 0x6; // that which is 2 shall become 4, and vice versa
|
||||
this.dataMask ^= (0xffff0000|0); // that which is 0x0000ffff shall become 0xffffffff, and vice versa
|
||||
this.setDataSize();
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesPrefix;
|
||||
this.stopCPU();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1628,12 +1627,11 @@ X86.opOS = function OS()
|
|||
X86.opAS = function AS()
|
||||
{
|
||||
if (I386) {
|
||||
this.opFlags |= X86.OPFLAG.SEG;
|
||||
this.opFlags |= X86.OPFLAG.ADDRSIZE;
|
||||
this.addrSize ^= 0x06; // that which is 2 shall become 4, and vice versa
|
||||
this.addrMask ^= (0xffff0000|0); // that which is 0x0000ffff shall become 0xffffffff, and vice versa
|
||||
this.setAddrSize();
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesPrefix;
|
||||
this.stopCPU();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -2618,7 +2616,7 @@ X86.opCWD = function CWD()
|
|||
*/
|
||||
X86.opCALLF = function CALLF()
|
||||
{
|
||||
X86.fnCALLF.call(this, this.getIPWord(), this.getIPWord());
|
||||
X86.fnCALLF.call(this, this.getIPWord(), this.getIPShort());
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesCallF;
|
||||
};
|
||||
|
||||
|
|
@ -3887,7 +3885,7 @@ X86.opJMP = function JMP()
|
|||
*/
|
||||
X86.opJMPF = function JMPF()
|
||||
{
|
||||
this.setCSIP(this.getIPWord(), this.getIPWord());
|
||||
this.setCSIP(this.getIPWord(), this.getIPShort());
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpF;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue