More 80386 support, and an audio API change forced by Chrome

This commit is contained in:
Jeff Parsons 2015-03-06 19:33:35 -08:00 committed by jeffpar
commit d3d431eb2c
9 changed files with 2406 additions and 2358 deletions

View file

@ -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);

View file

@ -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)) {

View file

@ -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;

View file

@ -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) {

View file

@ -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;
};