Groundwork laid for upcoming BACKTRACK support

This commit is contained in:
Jeff Parsons 2014-12-23 16:02:41 -08:00 committed by jeffpar
commit 2034428e9f
17 changed files with 5524 additions and 3147 deletions

View file

@ -221,7 +221,7 @@ module.exports = function(grunt) {
*/
compilation_level: "ADVANCED_OPTIMIZATIONS",
externs: pkg.closureCompilerExterns,
define: ["'SITEHOST=\"www.pcjs.org\"'", "'COMPILED=true'", "'DEBUG=false'", "'MAXDEBUG=false'"],
define: ["'SITEHOST=\"www.pcjs.org\"'", "'COMPILED=true'", "'DEBUG=false'", "'BACKTRACK=false'"],
warning_level: "verbose",
// jscomp_off: ["checkTypes", "fileoverviewTags"],
// summary_detail_level: 3,
@ -260,7 +260,7 @@ module.exports = function(grunt) {
TEMPcompilerOpts: {
// create_source_map: "./tmp/c1pjs/" + pkg.version + "/c1p.map",
define: ["\"APPNAME='C1Pjs'\"", "\"APPVERSION='" + pkg.version + "'\"", "DEBUGGER=false",
"\"SITEHOST='www.pcjs.org'\"", "COMPILED=true", "DEBUG=false", "MAXDEBUG=false"],
"\"SITEHOST='www.pcjs.org'\"", "COMPILED=true", "DEBUG=false", "BACKTRACK=false"],
// output_wrapper: "\"(function(){%output%})();//@ sourceMappingURL=/tmp/c1pjs/" + pkg.version + "/c1p.map\""
output_wrapper: "\"(function(){%output%})();\""
},
@ -272,7 +272,7 @@ module.exports = function(grunt) {
TEMPcompilerOpts: {
// create_source_map: "./tmp/c1pjs/" + pkg.version + "/c1p-dbg.map",
define: ["\"APPNAME='C1Pjs'\"", "\"APPVERSION='" + pkg.version + "'\"",
"\"SITEHOST='www.pcjs.org'\"", "COMPILED=true", "DEBUG=false", "MAXDEBUG=false"],
"\"SITEHOST='www.pcjs.org'\"", "COMPILED=true", "DEBUG=false", "BACKTRACK=false"],
// output_wrapper: "\"(function(){%output%})();//@ sourceMappingURL=/tmp/c1pjs/" + pkg.version + "/c1p-dbg.map\""
output_wrapper: "\"(function(){%output%})();\""
},
@ -284,7 +284,7 @@ module.exports = function(grunt) {
TEMPcompilerOpts: {
// create_source_map: "./tmp/pcjs/" + pkg.version + "/pc.map",
define: ["\"APPNAME='PCjs'\"", "\"APPVERSION='" + pkg.version + "'\"", "DEBUGGER=false",
"\"SITEHOST='www.pcjs.org'\"", "COMPILED=true", "DEBUG=false", "MAXDEBUG=false"],
"\"SITEHOST='www.pcjs.org'\"", "COMPILED=true", "DEBUG=false", "BACKTRACK=false"],
// output_wrapper: "\"(function(){%output%})();//@ sourceMappingURL=/tmp/pcjs/" + pkg.version + "/pc.map\""
output_wrapper: "\"(function(){%output%})();\""
},
@ -299,7 +299,7 @@ module.exports = function(grunt) {
TEMPcompilerOpts: {
// create_source_map: "./tmp/pcjs/" + pkg.version + "/pc-dbg.map",
define: ["\"APPNAME='PCjs'\"", "\"APPVERSION='" + pkg.version + "'\"",
"\"SITEHOST='www.pcjs.org'\"", "COMPILED=true", "DEBUG=false", "MAXDEBUG=false"],
"\"SITEHOST='www.pcjs.org'\"", "COMPILED=true", "DEBUG=false", "BACKTRACK=false"],
// output_wrapper: "\"(function(){%output%})();//@ sourceMappingURL=/tmp/pcjs/" + pkg.version + "/pc-dbg.map\""
output_wrapper: "\"(function(){%output%})();\""
},

View file

@ -275,43 +275,52 @@ function genMode(d, w, mrm, sGroup, sRO) {
var sRegGet = null;
var sRegSet = null;
var sRegSetBegin = "", sRegSetEnd = "";
var sRegBTLo = null, sRegBTHi = null;
if (!w) {
switch (reg) {
case 0:
sRegGet = "this.regAX & 0xff";
sRegSet = "this.regAX = (this.regAX & ~0xff) | ";
sRegBTLo = "this.backTrack.btiAL";
break;
case 1:
sRegGet = "this.regCX & 0xff";
sRegSet = "this.regCX = (this.regCX & ~0xff) | ";
sRegBTLo = "this.backTrack.btiCL";
break;
case 2:
sRegGet = "this.regDX & 0xff";
sRegSet = "this.regDX = (this.regDX & ~0xff) | ";
sRegBTLo = "this.backTrack.btiDL";
break;
case 3:
sRegGet = "this.regBX & 0xff";
sRegSet = "this.regBX = (this.regBX & ~0xff) | ";
sRegBTLo = "this.backTrack.btiBL";
break;
case 4:
sRegGet = "this.regAX >> 8";
sRegSet = "this.regAX = (this.regAX & 0xff) | ";
sRegSetEnd = " << 8";
sRegBTLo = "this.backTrack.btiAH";
break;
case 5:
sRegGet = "this.regCX >> 8";
sRegSet = "this.regCX = (this.regCX & 0xff) | ";
sRegSetEnd = " << 8";
sRegBTLo = "this.backTrack.btiCH";
break;
case 6:
sRegGet = "this.regDX >> 8";
sRegSet = "this.regDX = (this.regDX & 0xff) | ";
sRegSetEnd = " << 8";
sRegBTLo = "this.backTrack.btiDH";
break;
case 7:
sRegGet = "this.regBX >> 8";
sRegSet = "this.regBX = (this.regBX & 0xff) | ";
sRegSetEnd = " << 8";
sRegBTLo = "this.backTrack.btiBH";
break;
default:
sError = "unrecognized w=0 reg: " + reg;
@ -322,27 +331,43 @@ function genMode(d, w, mrm, sGroup, sRO) {
switch (reg) {
case 0:
sRegGet = "this.regAX";
sRegBTLo = "this.backTrack.btiAL";
sRegBTHi = "this.backTrack.btiAH";
break;
case 1:
sRegGet = "this.regCX";
sRegBTLo = "this.backTrack.btiCL";
sRegBTHi = "this.backTrack.btiCH";
break;
case 2:
sRegGet = "this.regDX";
sRegBTLo = "this.backTrack.btiDL";
sRegBTHi = "this.backTrack.btiDH";
break;
case 3:
sRegGet = "this.regBX";
sRegBTLo = "this.backTrack.btiBL";
sRegBTHi = "this.backTrack.btiBH";
break;
case 4:
sRegGet = "this.regSP";
sRegBTLo = "X86CPU.BACKTRACK.SP_LO";
sRegBTHi = "X86CPU.BACKTRACK.SP_HI";
break;
case 5:
sRegGet = "this.regBP";
sRegBTLo = "this.backTrack.btiBPLo";
sRegBTHi = "this.backTrack.btiBPHi";
break;
case 6:
sRegGet = "this.regSI";
sRegBTLo = "this.backTrack.btiSILo";
sRegBTHi = "this.backTrack.btiSIHi";
break;
case 7:
sRegGet = "this.regDI";
sRegBTLo = "this.backTrack.btiDILo";
sRegBTHi = "this.backTrack.btiDIHi";
break;
default:
sError = "unrecognized w=1 reg: " + reg;
@ -363,6 +388,7 @@ function genMode(d, w, mrm, sGroup, sRO) {
var sModRegGet = null;
var sModRegSet = null;
var sModRegSetBegin = "", sModRegSetEnd = "";
var sModRegBTLo = null, sModRegBTHi = null;
var sModRegSeg = "this.segData";
switch (mod) {
case 0:
@ -370,44 +396,44 @@ function genMode(d, w, mrm, sGroup, sRO) {
case 0:
sModAddr = "this.regBX + this.regSI";
sModFunc = "BXSI";
nCycles = "this.nEACyclesBaseIndex"; // 8086: 7
nCycles = "this.CYCLES.nEACyclesBaseIndex"; // 8086: 7
break;
case 1:
sModAddr = "this.regBX + this.regDI";
sModFunc = "BXDI";
nCycles = "this.nEACyclesBaseIndexExtra"; // 8086: 8
nCycles = "this.CYCLES.nEACyclesBaseIndexExtra"; // 8086: 8
break;
case 2:
sModAddr = "this.regBP + this.regSI";
sModFunc = "BPSI";
sModRegSeg = "this.segStack";
nCycles = "this.nEACyclesBaseIndexExtra"; // 8086: 8
nCycles = "this.CYCLES.nEACyclesBaseIndexExtra"; // 8086: 8
break;
case 3:
sModAddr = "this.regBP + this.regDI";
sModFunc = "BPDI";
sModRegSeg = "this.segStack";
nCycles = "this.nEACyclesBaseIndex"; // 8086: 7
nCycles = "this.CYCLES.nEACyclesBaseIndex"; // 8086: 7
break;
case 4:
sModAddr = "this.regSI";
sModFunc = "SI";
nCycles = "this.nEACyclesBase"; // 8086: 5
nCycles = "this.CYCLES.nEACyclesBase"; // 8086: 5
break;
case 5:
sModAddr = "this.regDI";
sModFunc = "DI";
nCycles = "this.nEACyclesBase"; // 8086: 5
nCycles = "this.CYCLES.nEACyclesBase"; // 8086: 5
break;
case 6:
sModAddr = "this.getIPWord()";
sModFunc = "D16";
nCycles = "this.nEACyclesDisp"; // 8086: 6
nCycles = "this.CYCLES.nEACyclesDisp"; // 8086: 6
break;
case 7:
sModAddr = "this.regBX";
sModFunc = "BX";
nCycles = "this.nEACyclesBase"; // 8086: 5
nCycles = "this.CYCLES.nEACyclesBase"; // 8086: 5
break;
default:
sError = "unrecognized mod=0 r/m: " + r_m;
@ -419,45 +445,45 @@ function genMode(d, w, mrm, sGroup, sRO) {
case 0:
sModAddr = "this.regBX + this.regSI + this.getIPDisp()";
sModFunc = "BXSID8";
nCycles = "this.nEACyclesBaseIndexDisp"; // 8086: 11
nCycles = "this.CYCLES.nEACyclesBaseIndexDisp"; // 8086: 11
break;
case 1:
sModAddr = "this.regBX + this.regDI + this.getIPDisp()";
sModFunc = "BXDID8";
nCycles = "this.nEACyclesBaseIndexDispExtra"; // 8086: 12
nCycles = "this.CYCLES.nEACyclesBaseIndexDispExtra"; // 8086: 12
break;
case 2:
sModAddr = "this.regBP + this.regSI + this.getIPDisp()";
sModFunc = "BPSID8";
sModRegSeg = "this.segStack";
nCycles = "this.nEACyclesBaseIndexDispExtra"; // 8086: 12
nCycles = "this.CYCLES.nEACyclesBaseIndexDispExtra"; // 8086: 12
break;
case 3:
sModAddr = "this.regBP + this.regDI + this.getIPDisp()";
sModFunc = "BPDID8";
sModRegSeg = "this.segStack";
nCycles = "this.nEACyclesBaseIndexDisp"; // 8086: 11
nCycles = "this.CYCLES.nEACyclesBaseIndexDisp"; // 8086: 11
break;
case 4:
sModAddr = "this.regSI + this.getIPDisp()";
sModFunc = "SID8";
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
break;
case 5:
sModAddr = "this.regDI + this.getIPDisp()";
sModFunc = "DID8";
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
break;
case 6:
sModAddr = "this.regBP + this.getIPDisp()";
sModFunc = "BPD8";
sModRegSeg = "this.segStack";
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
break;
case 7:
sModAddr = "this.regBX + this.getIPDisp()";
sModFunc = "BXD8";
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
break;
default:
sError = "unrecognized mod=1 r/m: " + r_m;
@ -469,45 +495,45 @@ function genMode(d, w, mrm, sGroup, sRO) {
case 0:
sModAddr = "this.regBX + this.regSI + this.getIPWord()";
sModFunc = "BXSID16";
nCycles = "this.nEACyclesBaseIndexDisp"; // 8086: 11
nCycles = "this.CYCLES.nEACyclesBaseIndexDisp"; // 8086: 11
break;
case 1:
sModAddr = "this.regBX + this.regDI + this.getIPWord()";
sModFunc = "BXDID16";
nCycles = "this.nEACyclesBaseIndexDispExtra"; // 8086: 12
nCycles = "this.CYCLES.nEACyclesBaseIndexDispExtra"; // 8086: 12
break;
case 2:
sModAddr = "this.regBP + this.regSI + this.getIPWord()";
sModFunc = "BPSID16";
sModRegSeg = "this.segStack";
nCycles = "this.nEACyclesBaseIndexDispExtra"; // 8086: 12
nCycles = "this.CYCLES.nEACyclesBaseIndexDispExtra"; // 8086: 12
break;
case 3:
sModAddr = "this.regBP + this.regDI + this.getIPWord()";
sModFunc = "BPDID16";
sModRegSeg = "this.segStack";
nCycles = "this.nEACyclesBaseIndexDisp"; // 8086: 11
nCycles = "this.CYCLES.nEACyclesBaseIndexDisp"; // 8086: 11
break;
case 4:
sModAddr = "this.regSI + this.getIPWord()";
sModFunc = "SID16";
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
break;
case 5:
sModAddr = "this.regDI + this.getIPWord()";
sModFunc = "DID16";
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
break;
case 6:
sModAddr = "this.regBP + this.getIPWord()";
sModFunc = "BPD16";
sModRegSeg = "this.segStack";
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
break;
case 7:
sModAddr = "this.regBX + this.getIPWord()";
sModFunc = "BXD16";
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
break;
default:
sError = "unrecognized mod=2 r/m: " + r_m;
@ -520,38 +546,46 @@ function genMode(d, w, mrm, sGroup, sRO) {
case 0:
sModRegGet = "this.regAX & 0xff";
sModRegSet = "this.regAX = (this.regAX & ~0xff) | ";
sModRegBTLo = "this.backTrack.btiAL";
break;
case 1:
sModRegGet = "this.regCX & 0xff";
sModRegSet = "this.regCX = (this.regCX & ~0xff) | ";
sModRegBTLo = "this.backTrack.btiCL";
break;
case 2:
sModRegGet = "this.regDX & 0xff";
sModRegSet = "this.regDX = (this.regDX & ~0xff) | ";
sModRegBTLo = "this.backTrack.btiDL";
break;
case 3:
sModRegGet = "this.regBX & 0xff";
sModRegSet = "this.regBX = (this.regBX & ~0xff) | ";
sModRegBTLo = "this.backTrack.btiBL";
break;
case 4:
sModRegGet = "this.regAX >> 8";
sModRegSet = "this.regAX = (this.regAX & 0xff) | ";
sModRegSetEnd = " << 8";
sModRegBTLo = "this.backTrack.btiAH";
break;
case 5:
sModRegGet = "this.regCX >> 8";
sModRegSet = "this.regCX = (this.regCX & 0xff) | ";
sModRegSetEnd = " << 8";
sModRegBTLo = "this.backTrack.btiCH";
break;
case 6:
sModRegGet = "this.regDX >> 8";
sModRegSet = "this.regDX = (this.regDX & 0xff) | ";
sModRegSetEnd = " << 8";
sModRegBTLo = "this.backTrack.btiDH";
break;
case 7:
sModRegGet = "this.regBX >> 8";
sModRegSet = "this.regBX = (this.regBX & 0xff) | ";
sModRegSetEnd = " << 8";
sModRegBTLo = "this.backTrack.btiBH";
break;
default:
sError = "unrecognized w=0 mod=3 r/m: " + r_m;
@ -562,27 +596,43 @@ function genMode(d, w, mrm, sGroup, sRO) {
switch (r_m) {
case 0:
sModRegGet = "this.regAX";
sModRegBTLo = "this.backTrack.btiAL";
sModRegBTHi = "this.backTrack.btiAH";
break;
case 1:
sModRegGet = "this.regCX";
sModRegBTLo = "this.backTrack.btiCL";
sModRegBTHi = "this.backTrack.btiCH";
break;
case 2:
sModRegGet = "this.regDX";
sModRegBTLo = "this.backTrack.btiDL";
sModRegBTHi = "this.backTrack.btiDH";
break;
case 3:
sModRegGet = "this.regBX";
sModRegBTLo = "this.backTrack.btiBL";
sModRegBTHi = "this.backTrack.btiBH";
break;
case 4:
sModRegGet = "this.regSP";
sModRegBTLo = "X86CPU.BACKTRACK.SP_LO";
sModRegBTHi = "X86CPU.BACKTRACK.SP_HI";
break;
case 5:
sModRegGet = "this.regBP";
sModRegBTLo = "this.backTrack.btiBPLo";
sModRegBTHi = "this.backTrack.btiBPHi";
break;
case 6:
sModRegGet = "this.regSI";
sModRegBTLo = "this.backTrack.btiSILo";
sModRegBTHi = "this.backTrack.btiSIHi";
break;
case 7:
sModRegGet = "this.regDI";
sModRegBTLo = "this.backTrack.btiDILo";
sModRegBTHi = "this.backTrack.btiDIHi";
break;
default:
sError = "unrecognized w=1 mod=3 r/m: " + r_m;
@ -614,17 +664,18 @@ function genMode(d, w, mrm, sGroup, sRO) {
}
print(" /**");
print(" * " + sOpMod + "(afnGrp, fnSrc): mod=" + toMod(d, mod) + " reg=" + toReg(d, w, reg, sGroup) + " r/m=" + toRM(mod, w, r_m));
print(" *");
print(" * @this {X86CPU}");
print(" * @param {Array.<function(number,number)>} afnGrp");
print(" * @param {function()} fnSrc");
print(" *");
print(" * mod=" + toMod(d, mod) + " reg=" + toReg(d, w, reg, sGroup) + " r/m=" + toRM(mod, w, r_m));
print(" */");
print(" " + sOpMod + ": function(afnGrp, fnSrc) {");
if (sModAddr) {
if (sModAddr.indexOf("+") > 0)
if (sModAddr.indexOf("+") > 0) {
sModAddr = "((" + sModAddr + ") & 0xffff)";
}
if (!d) {
if (reg == 7 && sRO) {
if (sModFunc) {
@ -681,6 +732,15 @@ function genMode(d, w, mrm, sGroup, sRO) {
print(" var " + sTemp + " = afnGrp[" + reg + "].call(this, " + sModRegGet + ", fnSrc.call(this));");
print(" " + sModRegSet + sModRegSetBegin + sTemp + sModRegSetEnd + ";");
}
if (sModRegBTLo) {
if (!sModRegBTHi) {
print(" if (BACKTRACK) " + sModRegBTLo + " = this.backTrack.btiMemLo;");
} else {
print(" if (BACKTRACK) {");
print(" " + sModRegBTLo + " = this.backTrack.btiMemLo; " + sModRegBTHi + " = this.backTrack.btiMemHi;");
print(" }");
}
}
}
}
}
@ -697,21 +757,31 @@ function genMode(d, w, mrm, sGroup, sRO) {
}
print(" /**");
print(" * " + sOpMod + "(fn): mod=" + toMod(d, mod) + " reg=" + toReg(d, w, reg) + " r/m=" + toRM(mod, w, r_m));
print(" *");
print(" * @this {X86CPU}");
print(" * @param {function(number,number)} fn (dst,src)");
print(" *");
print(" * mod=" + toMod(d, mod) + " reg=" + toReg(d, w, reg) + " r/m=" + toRM(mod, w, r_m));
print(" */");
print(" " + sOpMod + ": function(fn) {");
if (sModAddr && sRegGet) {
if (sModAddr.indexOf("+") > 0)
if (sModAddr.indexOf("+") > 0) {
sModAddr = "((" + sModAddr + ") & 0xffff)";
}
if (!d) {
if (sModFunc) {
if (fInline) {
print(" var " + sTemp + " = fn.call(this, this.modEA" + aSize[w] + "(" + sModRegSeg + ", " + sModAddr + "), " + sRegGet + ");");
if (sRegBTLo) {
if (!sRegBTHi) {
print(" if (BACKTRACK) this.backTrack.btiMemLo = " + sRegBTLo + ";");
} else {
print(" if (BACKTRACK) {");
print(" this.backTrack.btiMemLo = " + sRegBTLo + "; this.backTrack.btiMemHi = " + sRegBTHi + ";");
print(" }");
}
}
print(" this.setEA" + aSize[w] + "(" + sTemp + ");");
} else {
sModFunc = "write" + sModFunc + aSize[w];
@ -723,6 +793,15 @@ function genMode(d, w, mrm, sGroup, sRO) {
} else {
print(" this.regEAWrite = " + sModRegSeg + "[1] + " + sModAddr + ";");
print(" var " + sTemp + " = fn.call(this, this.modEA" + aSize[w] + "(this.regEAWrite), " + sRegGet + ");");
if (sRegBTLo) {
if (!sRegBTHi) {
print(" if (BACKTRACK) this.backTrack.btiMemLo = " + sRegBTLo + ";");
} else {
print(" if (BACKTRACK) {");
print(" this.backTrack.btiMemLo = " + sRegBTLo + "; this.backTrack.btiMemHi = " + sRegBTHi + ";");
print(" }");
}
}
print(" this.setEA" + aSize[w] + "(this.regEAWrite, " + sTemp + ");");
}
}
@ -763,6 +842,15 @@ function genMode(d, w, mrm, sGroup, sRO) {
print(" " + sRegSet + sRegSetBegin + sTemp + sRegSetEnd + ";");
}
}
if (sRegBTLo && sRegBTLo.indexOf("this.") >= 0) {
if (!sRegBTHi) {
print(" if (BACKTRACK) " + sRegBTLo + " = this.backTrack.btiMemLo;");
} else {
print(" if (BACKTRACK) {");
print(" " + sRegBTLo + " = this.backTrack.btiMemLo; " + sRegBTHi + " = this.backTrack.btiMemHi;");
print(" }");
}
}
}
if (nCycles !== null)
print(" this.nStepCycles -= " + nCycles + ";");
@ -783,6 +871,15 @@ function genMode(d, w, mrm, sGroup, sRO) {
print(" var " + sTemp + " = fn.call(this, " + sModRegGet + ", " + sRegGet + ");");
print(" " + sModRegSet + sModRegSetBegin + sTemp + sModRegSetEnd + ";");
}
if (sModRegBTLo && sModRegBTLo.indexOf("this.") >= 0 && sRegBTLo && sModRegBTLo != sRegBTLo) {
if (!sModRegBTHi || !sRegBTHi) {
print(" if (BACKTRACK) " + sModRegBTLo + " = " + sRegBTLo + ";");
} else {
print(" if (BACKTRACK) {");
print(" " + sModRegBTLo + " = " + sRegBTLo + "; " + sModRegBTHi + " = " + sRegBTHi + ";");
print(" }");
}
}
}
else {
if (!sRegSet) {
@ -799,6 +896,15 @@ function genMode(d, w, mrm, sGroup, sRO) {
print(" var " + sTemp + " = fn.call(this, " + sRegGet + ", " + sModRegGet + ");");
print(" " + sRegSet + sRegSetBegin + sTemp + sRegSetEnd + ";");
}
if (sRegBTLo && sRegBTLo.indexOf("this.") >= 0 && sModRegBTLo && sRegBTLo != sModRegBTLo) {
if (!sRegBTHi || !sModRegBTHi) {
print(" if (BACKTRACK) " + sRegBTLo + " = " + sModRegBTLo + ";");
} else {
print(" if (BACKTRACK) {");
print(" " + sRegBTLo + " = " + sModRegBTLo + "; " + sRegBTHi + " = " + sModRegBTHi + ";");
print(" }");
}
}
}
}
}

View file

@ -8,7 +8,7 @@ functionality into major PC components, aka "devices". However, not every file
and "component" is an overloaded term, since *[Component](/docs/pcjs/component/)* is also the name of
the shared base class used for most PCjs devices (see [component.js](../../shared/lib/component.js)).
So it's best to refer to these files generically as "modules", and more specifically as "device modules"
whenever they implement a specific device (or set of devices, in the case of [*Chipset*](/docs/pcjs/chipset/)).
whenever they implement a specific device (or set of devices, in the case of [*ChipSet*](/docs/pcjs/chipset/)).
Examples of non-device modules include UI modules like [panel.js](panel.js) and [debugger.js](debugger.js),
and sub-modules like [x86opxx.js](x86opxx.js), [x86mods.js](x86mods.js) and [x86help.js](x86help.js)
@ -28,9 +28,11 @@ At the time of this writing, the order is:
* [shared/weblib.js](../../shared/lib/weblib.js)
* [shared/component.js](../../shared/lib/component.js)
* [pcjs/defines.js](defines.js)
* [pcjs/interrupts.js](interrupts.js)
* [pcjs/messages.js](messages.js)
* [pcjs/panel.js](panel.js)
* [pcjs/bus.js](bus.js)
* [pcjs/mem.js](mem.js)
* [pcjs/memory.js](memory.js)
* [pcjs/cpu.js](cpu.js)
* [pcjs/x86.js](x86.js)
* [pcjs/x86seg.js](x86seg.js)
@ -38,14 +40,14 @@ At the time of this writing, the order is:
* [pcjs/x86grps.js](x86grps.js)
* [pcjs/x86help.js](x86help.js)
* [pcjs/x86mods.js](x86mods.js)
* [pcjs/x86op0f.js](x86op0f.js)
* [pcjs/x86opxx.js](x86opxx.js)
* [pcjs/x86op0f.js](x86op0f.js)
* [pcjs/chipset.js](chipset.js)
* [pcjs/rom.js](rom.js)
* [pcjs/ram.js](ram.js)
* [pcjs/keyboard.js](keyboard.js)
* [pcjs/video.js](video.js)
* [pcjs/serial.js](serial.js)
* [pcjs/serialport.js](serialport.js)
* [pcjs/mouse.js](mouse.js)
* [pcjs/disk.js](disk.js)
* [pcjs/fdc.js](fdc.js)
@ -65,3 +67,50 @@ Some of the modules *can* be reordered or even omitted (eg, [debugger.js](debugg
To minimize ordering requirements, the init() handlers and constructors of all modules should avoid
referencing other modules. Device modules should define an initBus() notification handler, which the
[*Computer*](/docs/pcjs/computer/) will call after it has created/initialized the *Bus* object.
Features
---
[List of major existing features goes here]
### BackTrack Support
The next major feature to be implemented is referred to as BackTrack Support, or simply BackTracks. When BackTracks
are enabled, every memory location (at the byte level) may have an optional link back to its source.
All the code that a virtual machine initially executes enters the machine either via ROM or disk sectors, and as that
code executes, the machine is loading data into registers from memory locations and/or I/O ports and writing the results
to other memory locations and/or I/O ports. BackTracks keep track of that data flow, allowing us to examine the history
of any piece of data at any time, down to the byte level; while this feature could be extended to the bit level, it
would make the feature dramatically more expensive, both in terms of size and speed.
BackTrack values are currently encoded as 32-bit values with three parts:
- 16-bit Object Index (OI)
- 9-bit Byte Index (0-511), relative to the start of the object (BI)
- 6-bit Generation Index (0-63) (GI)
Let's look at one of the last things a ROM does during boot: load a disk sector into RAM. It will be up to the disk
controller (or DMA controller if one is used) to create a BackTrack object representing the sector that was read,
adding that object to a BackTrack Object array, and then associating the "Object Index" (OI) from that array with the
first byte of RAM where the sector was loaded. Subsequent bytes of RAM containing the rest of the sector will also
have associated indexes, but they will be "Object-Relative Indexes" or ORIs (eg, +1, +2, +3, ..., +511).
Similarly, when a chunk of memory is copied to another location, the first byte at the new location will have an
associated "Memory Index" or MI that refers to the first byte at the old location, and subsequent bytes will have
"Memory-Relative Indexes" or MRIs (eg, +1, +2, ..., +65535 for forward copies, or -1, -2, ..., -65535 for backward
copies). However, MRIs are optional, since every new memory location can simply use an MI to refer to the corresponding
old memory location -- and indeed, that's likely all the first iteration of BackTracks will do.
At this point, it's worth diving down a bit, and understanding what typical BackTrack indexes will look like. We want
them to be simple and low-overhead, so we'll stick with numbers (specifically, signed 32-bit values) to represent all
possible index values.
By biasing all absolute indexes by 65536, that allows values 1 through 65535 to represent relative indexes.
We also want to allow negative relative indexes -1 through -65535, so to keep things simple, we won't ANY negative
absolute indexes.
So, we choose a range for absolute MIs of 0x00010000 to 0x0100FFFF (for a maximum of 16Mb), and a range for absolute
OIs of 0x01010000 to 0x0101FFFF (for a maximum of 65536 objects).

View file

@ -35,10 +35,18 @@
if (typeof module !== 'undefined') {
var str = require("../../shared/lib/strlib");
var Component = require("../../shared/lib/component");
var Memory = require("./mem");
var Memory = require("./memory");
var State = require("./state");
}
/**
* @class BackTrack
* @property {Object} obj
* @property {number} off
* @property {number} slot
* @property {number} refs
*/
/**
* Bus(cpu, dbg)
*
@ -154,11 +162,36 @@ function Bus(parmsBus, cpu, dbg)
* Allocate empty Memory blocks to span the entire physical address space.
*/
this.initMemory();
if (BACKTRACK) {
/*
* BackTrack objects have the following properties:
*
* obj: a reference to the source object (eg, ROM object, Sector object)
* off: the offset within the source object that this object refers to
* slot: the slot in abtObjects which this object currently occupies
* refs: the number of memory references, as recorded by setBackTrackIndex()
*/
this.abtObjects = [];
this.cbtDeletions = 0;
}
this.setReady();
}
Component.subclass(Component, Bus);
if (BACKTRACK) {
Bus.BACKTRACK = {
SLOT_MAX: 32768,
SLOT_SHIFT: 16,
GEN_START: 1,
GEN_MAX: 64,
GEN_SHIFT: 9,
OFF_MAX: 512
};
}
/**
* initMemory()
*
@ -431,6 +464,80 @@ Bus.prototype.setWordDirect = function(addr, w)
this.aMemBlocks[iBlock & this.blockMask].writeByteDirect(0, (w >> 8) & 0xff);
};
/**
* addBackTrackObject(obj, bto, off)
*
* If bto is null, then we create bto (ie, an object that references obj and records off).
*
* If bto is NOT null, then we verify that off is within bto's range; if not, then we must
* create a new bto and return that instead.
*
* @this {Bus}
* @param {Object} obj
* @param {Object} bto
* @param {number} off
* @return {Object|null}
*/
Bus.prototype.addBackTrackObject = function(obj, bto, off)
{
if (BACKTRACK && obj) {
if (!bto || off < bto.off || off >= bto.off + Bus.BACKTRACK.OFF_MAX) {
var slot;
var cbtObjects = this.abtObjects.length;
bto = {obj: obj, off: off, slot: 0, refs: 0};
if (!this.cbtDeletions) {
slot = cbtObjects;
} else {
for (slot = 0; slot < cbtObjects; slot++) {
if (!this.abtObjects[slot]) {
this.cbtDeletions--;
break;
}
}
this.assert(slot < cbtObjects);
}
this.assert(slot < Bus.BACKTRACK.SLOT_MAX);
bto.slot = slot;
if (slot == cbtObjects) {
this.abtObjects.push(bto);
} else {
this.abtObjects[slot] = bto;
}
}
return bto;
}
return null;
};
/**
* setBackTrackIndex(addr, bto, off)
*
* @this {Bus}
* @param {number} addr is a physical (non-segmented) address
* @param {Object|null} bto
* @param {number} off
*/
Bus.prototype.setBackTrackIndex = function(addr, bto, off)
{
if (BACKTRACK && bto) {
this.assert(off - bto.off >= 0 && off - bto.off < Bus.BACKTRACK.OFF_MAX);
var bti = (bto.slot << Bus.BACKTRACK.SLOT_SHIFT) | (Bus.BACKTRACK.GEN_START << Bus.BACKTRACK.GEN_SHIFT) | (off - bto.off);
var btiPrev = this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].writeBackTrack(addr & this.blockLimit, bti);
if (btiPrev != bti) {
if (btiPrev) {
var slot = btiPrev >>> Bus.BACKTRACK.SLOT_SHIFT;
var btoPrev = this.abtObjects[slot];
this.assert(btoPrev && btoPrev.refs > 0);
if (!--btoPrev.refs) {
this.abtObjects[slot] = null;
this.cbtDeletions++;
}
}
bto.refs++;
}
}
};
/**
* saveMemory()
*

View file

@ -2747,6 +2747,7 @@ ChipSet.prototype.requestDMA = function(iDMAChannel, done)
/**
* advanceDMA(channel, fInit)
*
* @this {ChipSet}
* @param {Object} channel
* @param {boolean} [fInit]
*/
@ -2772,7 +2773,8 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
* I/O request, which will in turn trigger another async callback. Thus, the DMA request keeps itself going without
* requiring any special assistance from the CPU via setDMA().
*/
var obj = this;
var bto = null;
var chipset = this;
var fAsyncRequest = false;
var controller = channel.controller;
var iDMAChannel = controller.nChannelBase + channel.iChannel;
@ -2791,11 +2793,11 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
if (channel.xfer == ChipSet.DMA_MODE.XFER_WRITE) {
fAsyncRequest = true;
(function advanceDMAWrite(addrCur) {
channel.fnTransfer.call(channel.component, channel.obj, -1, function onTransferDMA(b, fAsync) {
channel.fnTransfer.call(channel.component, channel.obj, -1, function onTransferDMA(b, fAsync, obj, off) {
if (b < 0) {
if (!channel.fWarning) {
if (DEBUG && obj.messageEnabled(Messages.DMA)) {
obj.messagePrint("advanceDMA(" + iDMAChannel + ") ran out of data, assuming 0xff", true);
if (DEBUG && chipset.messageEnabled(Messages.DMA)) {
chipset.messagePrint("advanceDMA(" + iDMAChannel + ") ran out of data, assuming 0xff", true);
}
channel.fWarning = true;
}
@ -2807,18 +2809,20 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
if (!channel.masked) {
/*
* While it makes sense to call bus.setByteDirect(), since DMA deals with physical memory,
* we lose the ability to trap accesses with write breakpoints by not using obj.cpu.setByte().
* we lose the ability to trap accesses with write breakpoints by not using chipset.cpu.setByte().
*
* TODO: Consider providing a Bus memory interface that honors write breakpoints.
*/
obj.bus.setByteDirect(addrCur, b);
chipset.bus.setByteDirect(addrCur, b);
if (BACKTRACK) {
bto = chipset.bus.addBackTrackObject(obj, bto, off);
chipset.bus.setBackTrackIndex(addrCur, bto, off);
}
}
fAsyncRequest = fAsync;
if (fAsync) {
setTimeout(function() {
if (!obj.updateDMA(channel)) {
obj.advanceDMA(channel);
}
if (!chipset.updateDMA(channel)) chipset.advanceDMA(channel);
}, 0);
}
});
@ -2827,12 +2831,12 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
else if (channel.xfer == ChipSet.DMA_MODE.XFER_READ) {
/*
* While it makes sense to call bus.getByteDirect(), since DMA deals with physical memory,
* we lose the ability to trap accesses with read breakpoints by not using obj.cpu.getByte().
* we lose the ability to trap accesses with read breakpoints by not using chipset.cpu.getByte().
*
* TODO: Determine whether we should support async dmaWrite() functions (currently not required),
* and consider providing a Bus memory interface that honors read breakpoints.
*/
b = obj.bus.getByteDirect(addr);
b = chipset.bus.getByteDirect(addr);
if (channel.fnTransfer.call(channel.component, channel.obj, b) < 0) {
/*
* In this case, I think I have no choice but to terminate the DMA operation in response to a failure,
@ -2856,6 +2860,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
/**
* updateDMA(channel)
*
* @this {ChipSet}
* @param {Object} channel
* @return {boolean} true if DMA operation complete, false if not
*/

View file

@ -108,7 +108,19 @@ var TYPEDARRAYS = false; // (typeof ArrayBuffer !== 'undefined');
/**
* @define {boolean}
*
* Enable instruction sampling (work-in-progress).
* Enable backtracking (disabled in compiled versions). Backtracking is a mechanism that allows us to tag
* every byte of incoming data and follow the flow of that data.
*/
var BACKTRACK = true;
/**
* @define {boolean}
*
* Enable instruction sampling (a work-in-progress). This was used briefly as an internal debugging aid, to
* periodically record EIP values in a fixed-length sampling buffer, halting execution once the sampling buffer
* was full, and then compare those sampled EIP values to corresponding EIP values on subsequent runs, to look
* for deviations. In theory, every run is supposed to be absolutely identical, even if you interrupt execution
* with the Debugger or enable/disable different sets of messages, but in practice, that's hard to guarantee.
*/
var SAMPLER = false;

View file

@ -66,8 +66,8 @@
* ---
* Originally, when the Disk class was given a disk image to load and mount, it would request the
* ENTIRE disk image from the DiskDump module. That works well for small (floppy) disk images, but
* for larger disks -- let's just say anything stored on the server as an IMG file -- we'd prefer
* to interact with that disk using "On-Demand I/O". Any IMG file on the same server as the PCjs
* for larger disks -- let's just say anything stored on the server as an "img" file -- we'd prefer
* to interact with that disk using "On-Demand I/O". Any "img" file on the same server as the PCjs
* application should be a candidate for on-demand access.
*
* On-Demand I/O means that nothing is initially transferred from the server. As sectors are
@ -558,7 +558,7 @@ Disk.prototype.load = function(sDiskName, sDiskPath, file, fnNotify, controller)
* driveConfig 'size' parm, or to match the capacity required by the driveConfig 'type' parameter.
*
* If a 'disk' is specified, we pass mbhd=0, because the actual size will depend on the image.
* However, I don't currently have any .DSK or .IMG files containing hard disk images; those formats
* However, I don't currently have any "dsk" or "img" files containing hard disk images; those formats
* were really intended for floppy disk images. If I never create any hard disk image files, then
* we can simply eliminate sSizeParm in the 'disk' case.
*
@ -781,9 +781,9 @@ Disk.prototype.doneLoad = function(sDiskFile, sDiskData, nErrorCode, sDiskPath)
/*
* Before the image is usable, we must "normalize" all the sectors. In the past, this meant
* "inflating" them all. However, that's no longer strictly necessary. Mainly, it just means
* setting 'length', 'pattern' and 'data' properties, so that all the sectors are well-defined.
* This includes detecting sector data in older formats (eg, the OLD array of 'bytes' instead
* of the NEW 'data' array of dwords) and converting them on-the-fly to the current format.
* setting 'length', 'data', and 'pattern' properties, so that all the sectors are well-defined.
* This includes detecting sector data in older formats (eg, the old array of 'bytes' instead
* of the new 'data' array of dwords) and converting them on-the-fly to the current format.
*/
this.nCylinders = aDiskData.length;
this.nHeads = aDiskData[0].length;

View file

@ -1104,8 +1104,8 @@ FDC.prototype.copyDrive = function(iDrive)
*
* Also note that in an actual FDC request, drive.nBytes is initialized to the size of a single sector; the extent
* of the entire transfer is actually determined by a count that has been pre-loaded into the DMA controller. The FDC
* isn't even aware of the extent of the transfer, so in the case of a read request, all readByte() can do is return bytes
* until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted.
* isn't even aware of the extent of the transfer, so in the case of a read request, all readByte() can do is return
* bytes until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted.
*
* Since seekDrive() is for use with non-DMA requests, we use nBytes to specify the length of the entire transfer.
*
@ -2281,7 +2281,7 @@ FDC.prototype.doFormat = function(drive)
};
/**
* readByte(drive)
* readByte(drive, done)
*
* The following drive properties must have been setup prior to our first call:
*
@ -2301,16 +2301,21 @@ FDC.prototype.doFormat = function(drive)
*
* @this {FDC}
* @param {Object} drive
* @param {function(number,boolean)} done (number is next available byte from drive, or -1 if no more bytes available)
* @param {function(number,boolean,Object,number)} done (number is next available byte from drive, or -1 if no more bytes available)
*/
FDC.prototype.readByte = function(drive, done)
{
var b = -1;
var obj, off; // these variables are purely for BACKTRACK purposes
if (!drive.resCode && drive.disk) {
do {
if (drive.sector) {
if ((b = drive.disk.read(drive.sector, drive.ibSector++)) >= 0)
off = drive.ibSector;
if ((b = drive.disk.read(drive.sector, drive.ibSector++)) >= 0) {
obj = drive.sector;
break;
}
}
/*
* Locate the next sector, and then try reading again.
@ -2328,7 +2333,7 @@ FDC.prototype.readByte = function(drive, done)
this.advanceSector(drive);
} while (true);
}
done(b, false);
done(b, false, obj, off);
};
/**

View file

@ -101,7 +101,10 @@ if (typeof module !== 'undefined') {
* @param {boolean} [fReadOnly] is true if the block must be marked read-only
* @param {Object} [controller] is an optional memory controller component
*/
function Memory(addr, size, fReadOnly, controller) {
function Memory(addr, size, fReadOnly, controller)
{
var i;
this.cb = size || 0;
this.adw = null;
this.offset = 0;
@ -109,6 +112,18 @@ function Memory(addr, size, fReadOnly, controller) {
this.controller = null;
this.fDirty = this.fDirtyEver = false;
if (BACKTRACK) {
if (this.fReadOnly || !size || controller) {
this.readBackTrack = Memory.readBackTrackNone;
this.writeBackTrack = Memory.writeBackTrackNone;
} else {
this.readBackTrack = Memory.readBackTrackIndex;
this.writeBackTrack = Memory.writeBackTrackIndex;
this.abtIndexes = new Array(size);
for (i = 0; i < size; i++) this.abtIndexes[i] = 0;
}
}
/*
* For empty memory blocks, all we need to do is ensure all access functions
* are mapped to "none" handlers.
@ -135,6 +150,9 @@ function Memory(addr, size, fReadOnly, controller) {
* This is the normal case: allocate a buffer that provides 8 bits of data per address;
* no controller is required because our default memory access functions (see afnMemory)
* know how to deal with this simple 1-1 mapping of addresses to bytes and words.
*
* TODO: Consider initializing the memory array to random (or pseudo-random) values in DEBUG
* mode; pseudo-random might be best, because if that uncovers a bug, it might be reproducible.
*/
if (TYPEDARRAYS) {
this.buffer = new ArrayBuffer(size);
@ -149,216 +167,307 @@ function Memory(addr, size, fReadOnly, controller) {
if (FATARRAYS) {
this.ab = new Array(size);
} else {
/*
* NOTE: This is the default mode of operation (!TYPEDARRAYS && !FATARRAYS), because it
* seems to provide the best performance; and although in theory, that performance might
* come at twice the overhead of TYPEDARRAYS, it's increasingly likely that the JavaScript
* runtime will notice that all we ever store are 32-bit values, and optimize accordingly.
*/
this.adw = new Array(size >> 2);
for (var i = 0; i < this.adw.length; i++) {
this.adw[i] = 0;
}
for (i = 0; i < this.adw.length; i++) this.adw[i] = 0;
}
this.setAccess(Memory.afnMemory);
}
}
Memory.prototype = {
constructor: Memory,
/**
* readNone(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
readNone: function(off) {
if (DEBUGGER && this.dbg.messageEnabled(Messages.MEM) /* && !off */) {
this.dbg.message("attempt to read invalid block %" + str.toHex(this.addr) + " from " + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel));
}
return 0;
},
/**
* writeNone(off, v)
*
* @this {Memory}
* @param {number} off
* @param {number} v (could be either a byte or word value, since we use the same handler for both kinds of accesses)
*/
writeNone: function(off, v) {
if (DEBUGGER && this.dbg.messageEnabled(Messages.MEM) /* && !off */) {
this.dbg.message("attempt to write 0x" + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true);
}
},
/**
* readByteMemory(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
readByteMemory: function readByteMemory(off) {
Component.assert(off >= 0 && off < this.cb);
if (FATARRAYS) {
return this.ab[off];
}
return ((this.adw[off >> 2] >>> ((off & 0x3) << 3)) & 0xff);
},
/**
* readWordMemory(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
readWordMemory: function readWordMemory(off) {
Component.assert(off >= 0 && off < this.cb - 1);
if (FATARRAYS) {
return this.ab[off] | (this.ab[off + 1] << 8);
}
var w;
/**
* readNone(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Memory.readNone = function readNone(off)
{
if (DEBUGGER && this.dbg.messageEnabled(Messages.MEM) /* && !off */) {
this.dbg.message("attempt to read invalid block %" + str.toHex(this.addr) + " from " + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel));
}
return 0;
};
/**
* writeNone(off, v)
*
* @this {Memory}
* @param {number} off
* @param {number} v (could be either a byte or word value, since we use the same handler for both kinds of accesses)
*/
Memory.writeNone = function writeNone(off, v) {
if (DEBUGGER && this.dbg.messageEnabled(Messages.MEM) /* && !off */) {
this.dbg.message("attempt to write 0x" + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true);
}
},
/**
* readByteMemory(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Memory.readByteMemory = function readByteMemory(off)
{
Component.assert(off >= 0 && off < this.cb);
if (FATARRAYS) {
return this.ab[off];
}
return ((this.adw[off >> 2] >>> ((off & 0x3) << 3)) & 0xff);
};
/**
* readWordMemory(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Memory.readWordMemory = function readWordMemory(off)
{
Component.assert(off >= 0 && off < this.cb - 1);
if (FATARRAYS) {
return this.ab[off] | (this.ab[off + 1] << 8);
}
var w;
var idw = off >> 2;
var nShift = (off & 0x3) << 3;
var dw = (this.adw[idw] >>> nShift);
if (nShift < 24) {
w = dw & 0xffff;
} else {
w = (dw & 0xff) | ((this.adw[idw + 1] & 0xff) << 8);
}
return w;
};
/**
* writeByteMemory(off, b)
*
* @this {Memory}
* @param {number} off
* @param {number} b
*/
Memory.writeByteMemory = function writeByteMemory(off, b)
{
Component.assert(off >= 0 && off < this.cb && (b & 0xff) == b);
if (FATARRAYS) {
this.ab[off] = b;
} else {
var idw = off >> 2;
var nShift = (off & 0x3) << 3;
this.adw[idw] = (this.adw[idw] & ~(0xff << nShift)) | (b << nShift);
}
this.fDirty = true;
};
/**
* writeWordMemory(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
Memory.writeWordMemory = function writeWordMemory(off, w)
{
Component.assert(off >= 0 && off < this.cb - 1 && (w & 0xffff) == w);
if (FATARRAYS) {
this.ab[off] = (w & 0xff);
this.ab[off + 1] = (w >> 8);
} else {
var idw = off >> 2;
var nShift = (off & 0x3) << 3;
var dw = (this.adw[idw] >>> nShift);
if (nShift < 24) {
w = dw & 0xffff;
this.adw[idw] = (this.adw[idw] & ~(0xffff << nShift)) | (w << nShift);
} else {
w = (dw & 0xff) | ((this.adw[idw + 1] & 0xff) << 8);
this.adw[idw] = (this.adw[idw] & 0x00ffffff) | (w << 24);
idw++;
this.adw[idw] = (this.adw[idw] & 0xffffff00) | (w >> 8);
}
return w;
},
/**
* writeByteMemory(off, b)
*
* @this {Memory}
* @param {number} off
* @param {number} b
*/
writeByteMemory: function writeByteMemory(off, b) {
Component.assert(off >= 0 && off < this.cb && (b & 0xff) == b);
if (FATARRAYS) {
this.ab[off] = b;
} else {
var idw = off >> 2;
var nShift = (off & 0x3) << 3;
this.adw[idw] = (this.adw[idw] & ~(0xff << nShift)) | (b << nShift);
}
this.fDirty = true;
},
/**
* writeWordMemory(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
writeWordMemory: function writeWordMemory(off, w) {
Component.assert(off >= 0 && off < this.cb - 1 && (w & 0xffff) == w);
if (FATARRAYS) {
this.ab[off] = (w & 0xff);
this.ab[off + 1] = (w >> 8);
} else {
var idw = off >> 2;
var nShift = (off & 0x3) << 3;
if (nShift < 24) {
this.adw[idw] = (this.adw[idw] & ~(0xffff << nShift)) | (w << nShift);
} else {
this.adw[idw] = (this.adw[idw] & 0x00ffffff) | (w << 24);
idw++;
this.adw[idw] = (this.adw[idw] & 0xffffff00) | (w >> 8);
}
}
this.fDirty = true;
},
/**
* readByteChecked(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
readByteChecked: function readByteChecked(off) {
if (DEBUGGER) this.dbg.checkMemoryRead(this.addr + off);
return this.readByteDirect(off);
},
/**
* readWordChecked(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
readWordChecked: function readWordChecked(off) {
if (DEBUGGER) {
this.dbg.checkMemoryRead(this.addr + off) || this.dbg.checkMemoryRead(this.addr + off + 1); // jshint ignore:line
}
return this.readWordDirect(off);
},
/**
* writeByteChecked(off, b)
*
* @this {Memory}
* @param {number} off
* @param {number} b
*/
writeByteChecked: function writeByteChecked(off, b) {
if (DEBUGGER) this.dbg.checkMemoryWrite(this.addr + off);
this.writeByteDirect(off, b);
},
/**
* writeWordChecked(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
writeWordChecked: function writeWordChecked(off, w) {
if (DEBUGGER) {
this.dbg.checkMemoryWrite(this.addr + off) || this.dbg.checkMemoryWrite(this.addr + off + 1); // jshint ignore:line
}
this.writeWordDirect(off, w);
},
/**
* readByteTypedArray(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
readByteTypedArray: function readByteTypedArray(off) {
Component.assert(off >= 0 && off < this.cb);
return this.ab[off];
},
/**
* readWordTypedArray(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
readWordTypedArray: function readWordTypedArray(off) {
Component.assert(off >= 0 && off < this.cb - 1);
return this.dv.getUint16(off, true);
},
/**
* writeByteTypedArray(off, b)
*
* @this {Memory}
* @param {number} off
* @param {number} b
*/
writeByteTypedArray: function writeByteTypedArray(off, b) {
Component.assert(off >= 0 && off < this.cb && (b & 0xff) == b);
this.ab[off] = b;
this.fDirty = true;
},
/**
* writeWordTypedArray(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
writeWordTypedArray: function writeWordTypedArray(off, w) {
Component.assert(off >= 0 && off < this.cb - 1 && (w & 0xffff) == w);
this.dv.setUint16(off, w, true);
this.fDirty = true;
},
}
this.fDirty = true;
};
/**
* readByteChecked(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Memory.readByteChecked = function readByteChecked(off)
{
if (DEBUGGER) this.dbg.checkMemoryRead(this.addr + off);
return this.readByteDirect(off);
};
/**
* readWordChecked(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Memory.readWordChecked = function readWordChecked(off)
{
if (DEBUGGER) {
this.dbg.checkMemoryRead(this.addr + off) || this.dbg.checkMemoryRead(this.addr + off + 1); // jshint ignore:line
}
return this.readWordDirect(off);
};
/**
* writeByteChecked(off, b)
*
* @this {Memory}
* @param {number} off
* @param {number} b
*/
Memory.writeByteChecked = function writeByteChecked(off, b)
{
if (DEBUGGER) this.dbg.checkMemoryWrite(this.addr + off);
this.writeByteDirect(off, b);
};
/**
* writeWordChecked(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
Memory.writeWordChecked = function writeWordChecked(off, w)
{
if (DEBUGGER) {
this.dbg.checkMemoryWrite(this.addr + off) || this.dbg.checkMemoryWrite(this.addr + off + 1); // jshint ignore:line
}
this.writeWordDirect(off, w);
};
/**
* readByteTypedArray(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Memory.readByteTypedArray = function readByteTypedArray(off)
{
Component.assert(off >= 0 && off < this.cb);
return this.ab[off];
};
/**
* readWordTypedArray(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Memory.readWordTypedArray = function readWordTypedArray(off)
{
Component.assert(off >= 0 && off < this.cb - 1);
return this.dv.getUint16(off, true);
};
/**
* writeByteTypedArray(off, b)
*
* @this {Memory}
* @param {number} off
* @param {number} b
*/
Memory.writeByteTypedArray = function writeByteTypedArray(off, b)
{
Component.assert(off >= 0 && off < this.cb && (b & 0xff) == b);
this.ab[off] = b;
this.fDirty = true;
};
/**
* writeWordTypedArray(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
Memory.writeWordTypedArray = function writeWordTypedArray(off, w)
{
Component.assert(off >= 0 && off < this.cb - 1 && (w & 0xffff) == w);
this.dv.setUint16(off, w, true);
this.fDirty = true;
};
/**
* readBackTrackNone(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Memory.readBackTrackNone = function readBackTrackNone(off)
{
return 0;
};
/**
* writeBackTrackNone(off, bti)
*
* @this {Memory}
* @param {number} off
* @param {number} bti
*/
Memory.writeBackTrackNone = function writeBackTrackNone(off, bti)
{
};
/**
* readBackTrackIndex(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Memory.readBackTrackIndex = function readBackTrackIndex(off)
{
Component.assert(off >= 0 && off < this.cb);
return this.abtIndexes[off];
};
/**
* writeBackTrackIndex(off, bti)
*
* @this {Memory}
* @param {number} off
* @param {number} bti
* @return {number} previous bti (0 if none)
*/
Memory.writeBackTrackIndex = function writeBackTrackIndex(off, bti)
{
var btiPrev;
Component.assert(off >= 0 && off < this.cb);
btiPrev = this.abtIndexes[off];
this.abtIndexes[off] = bti;
return btiPrev;
};
Memory.afnMemory = [Memory.readByteMemory, Memory.readWordMemory, Memory.writeByteMemory, Memory.writeWordMemory];
Memory.afnChecked = [Memory.readByteChecked, Memory.readWordChecked, Memory.writeByteChecked, Memory.writeWordChecked];
if (TYPEDARRAYS) {
Memory.afnTypedArray = [Memory.readByteTypedArray, Memory.readWordTypedArray, Memory.writeByteTypedArray, Memory.writeWordTypedArray];
}
Memory.prototype = {
constructor: Memory,
/**
* save()
*
@ -424,9 +533,9 @@ Memory.prototype = {
/*
* At this point, it's a consistency error for adw to be null; it's happened once already,
* when there was a restore bug in the Video component that added the frame buffer at the video
* card's "spec'ed" address instead of the programmed address, hence there were no controller-owned
* memory blocks installed at the programmed address, and so we arrived here at a block with no
* controller AND no data.
* card's "spec'ed" address instead of the programmed address, so there were no controller-owned
* memory blocks installed at the programmed address, and so we arrived here at a block with
* no controller AND no data.
*/
Component.assert(adw != null);
if (adw && this.cb == adw.length << 2) {
@ -473,11 +582,11 @@ Memory.prototype = {
* @param {boolean} [fDirect]
*/
setReadAccess: function(afn, fDirect) {
this.readByte = afn[0]? afn[0] : this.readNone;
this.readWord = afn[1]? afn[1] : this.readNone;
this.readByte = afn[0] || Memory.readNone;
this.readWord = afn[1] || Memory.readNone;
if (fDirect) {
this.readByteDirect = afn[0]? afn[0] : this.readNone;
this.readWordDirect = afn[1]? afn[1] : this.readNone;
this.readByteDirect = afn[0] || Memory.readNone;
this.readWordDirect = afn[1] || Memory.readNone;
}
},
/**
@ -488,11 +597,11 @@ Memory.prototype = {
* @param {boolean} [fDirect]
*/
setWriteAccess: function(afn, fDirect) {
this.writeByte = afn[2] && !this.fReadOnly? afn[2] : this.writeNone;
this.writeWord = afn[3] && !this.fReadOnly? afn[3] : this.writeNone;
this.writeByte = !this.fReadOnly && afn[2] || Memory.writeNone;
this.writeWord = !this.fReadOnly && afn[3] || Memory.writeNone;
if (fDirect) {
this.writeByteDirect = afn[2]? afn[2] : this.writeNone;
this.writeWordDirect = afn[3]? afn[3] : this.writeNone;
this.writeByteDirect = afn[2] || Memory.writeNone;
this.writeWordDirect = afn[3] || Memory.writeNone;
}
},
/**
@ -510,8 +619,8 @@ Memory.prototype = {
* @this {Memory}
*/
resetWriteAccess: function() {
this.writeByte = this.fReadOnly? this.writeNone : this.writeByteDirect;
this.writeWord = this.fReadOnly? this.writeNone : this.writeWordDirect;
this.writeByte = this.fReadOnly? Memory.writeNone : this.writeByteDirect;
this.writeWord = this.fReadOnly? Memory.writeNone : this.writeWordDirect;
},
/**
* setDebugInfo(cpu, dbg, addr, size)
@ -581,13 +690,6 @@ Memory.prototype = {
}
};
Memory.afnMemory = [Memory.prototype.readByteMemory, Memory.prototype.readWordMemory, Memory.prototype.writeByteMemory, Memory.prototype.writeWordMemory];
Memory.afnChecked = [Memory.prototype.readByteChecked, Memory.prototype.readWordChecked, Memory.prototype.writeByteChecked, Memory.prototype.writeWordChecked];
if (TYPEDARRAYS) {
Memory.afnTypedArray = [Memory.prototype.readByteTypedArray, Memory.prototype.readWordTypedArray, Memory.prototype.writeByteTypedArray, Memory.prototype.writeWordTypedArray];
}
if (typeof APP_PCJS !== 'undefined') APP_PCJS.Memory = Memory;
if (typeof module !== 'undefined') module.exports = Memory;

View file

@ -37,7 +37,7 @@ if (typeof module !== 'undefined') {
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var Messages = require("./messages");
var SerialPort = require("./serial");
var SerialPort = require("./serialport");
var State = require("./state");
}

View file

@ -90,21 +90,21 @@ Component.subclass(Component, ROM);
/*
* ROM BIOS Data Area (RBDA) definitions, in physical address form, using the same ALL-CAPS names
* found in the original IBM PC ROM BIOS listing.
*
* TODO: Fill in remaining RBDA holes.
* found in the original IBM PC ROM BIOS listing. TODO: Fill in remaining RBDA holes.
*/
ROM.BIOS = {};
ROM.BIOS.RS232_BASE = 0x400; // 4 (word) I/O addresses of RS-232 adapters
ROM.BIOS.PRINTER_BASE = 0x408; // 4 (word) I/O addresses of printer adapters
ROM.BIOS.EQUIP_FLAG = 0x410; // installed hardware (word)
ROM.BIOS.MFG_TEST = 0x412; // initialization flag (byte)
ROM.BIOS.MEMORY_SIZE = 0x413; // memory size in K-bytes (word)
ROM.BIOS.RESET_FLAG = 0x472; // set to 0x1234 if keyboard reset underway (word)
ROM.BIOS.RESET_FLAG_WARMBOOT = 0x1234; // value stored at ROM.BIOS.RESET_FLAG to indicate a "warm boot", bypassing memory tests
ROM.BIOS = {
RS232_BASE: 0x400, // 4 (word) I/O addresses of RS-232 adapters
PRINTER_BASE: 0x408, // 4 (word) I/O addresses of printer adapters
EQUIP_FLAG: 0x410, // installed hardware (word)
MFG_TEST: 0x412, // initialization flag (byte)
MEMORY_SIZE: 0x413, // memory size in K-bytes (word)
RESET_FLAG: 0x472 // set to 0x1234 if keyboard reset underway (word)
};
// RESET_FLAG is the traditional end of the RBDA, as originally defined at real-mode segment 0x40.
ROM.BIOS.RESET_FLAG_WARMBOOT = 0x1234; // value stored at ROM.BIOS.RESET_FLAG to indicate a "warm boot", bypassing memory tests
/*
* NOTE: There's currently no need for this component to have a reset() function, since
* once the ROM data is loaded, it can't be changed, so there's nothing to reinitialize.
@ -316,8 +316,13 @@ ROM.prototype.addROM = function(addr)
if (addr == null) return true;
if (this.bus.addMemory(addr, this.sizeROM, true)) {
if (DEBUG) this.log("addROM(): copying ROM to " + str.toHexAddr(addr) + " (0x" + str.toHex(this.abROM.length) + " bytes)");
var bto = null;
for (var i = 0; i < this.abROM.length; i++) {
this.bus.setByteDirect(addr + i, this.abROM[i]);
if (BACKTRACK) {
bto = this.bus.addBackTrackObject(this, bto, i);
this.bus.setBackTrackIndex(addr + i, bto, i);
}
}
return true;
}

View file

@ -1140,9 +1140,9 @@ if (DEBUGGER) Card.GRC.REGS = ["SRESET","ESRESET","COLRCMP","DATAROT","READMAP",
* we rely on the Memory object's "this.controller" property to give us access to the Card's state.
*
* And we take a little extra time to conditionally set fDirty on writes, meaning if a write did not actually
* change the value of the memory, we will not set fDirty. The default write functions in mem.js don't take that
* performance hit, but here, it may be worthwhile, because if it results in fewer dirty blocks, display updates
* may be faster.
* change the value of the memory, we will not set fDirty. The default write functions in memory.js don't take
* that performance hit, but here, it may be worthwhile, because if it results in fewer dirty blocks, display
* updates may be faster.
*
* Note that we don't have to worry about dealing with word accesses that straddle block boundaries, because
* the Bus component automatically breaks those accesses into separate byte requests. Similarly, byte and word

View file

@ -423,11 +423,18 @@ X86CPU.CYCLES_80286 = {
* that can easily be changed to 6 bytes if/when we decide to fully implement 8086 support
* (see X86CPU.PREFETCH.QUEUE). It's just not clear whether that support will be a goal.
*/
X86CPU.PREFETCH = {
QUEUE: 4,
ARRAY: 8, // smallest power-of-two > PREFETCH.QUEUE
MASK: 0x7 // (X86CPU.PREFETCH.ARRAY - 1)
};
X86CPU.PREFETCH = {};
X86CPU.PREFETCH.QUEUE = 4;
X86CPU.PREFETCH.ARRAY = 8; // smallest power-of-two > PREFETCH.QUEUE
X86CPU.PREFETCH.MASK = 0x7; // (X86CPU.PREFETCH.ARRAY - 1)
if (BACKTRACK) {
X86CPU.BACKTRACK = {
SP_LO: 0,
SP_HI: 0
};
}
/**
* initMemory(aMemBlocks, addrLimit, blockShift, blockLimit, blockMask)
@ -691,7 +698,7 @@ X86CPU.prototype.initProcessor = function()
this.CYCLES = (this.model >= X86.MODEL_80286? X86CPU.CYCLES_80286 : X86CPU.CYCLES_8088);
this.aOps = X86OpXX.aOps.slice(); // make a copy of aOps and others before modifying them
this.aOps = X86OpXX.aOps.slice(); // make copies of aOps and others before modifying them
this.aOpGrp4b = X86Grps.aOpGrp4b.slice();
this.aOpGrp4w = X86Grps.aOpGrp4w.slice();
this.aOpGrp6 = X86Op0F.aOpGrp6Real; // setProtMode() will ensure that aOpGrp6 is switched
@ -754,7 +761,6 @@ X86CPU.prototype.reset = function()
this.resetRegs();
this.resetCycles();
this.clearError(); // clear any fatal error/exception that setError() may have flagged
if (SAMPLER) {
this.iSampleNext = 0;
this.iSampleFreq = 0;
@ -767,21 +773,21 @@ X86CPU.prototype.reset = function()
*
* According to "The 8086 Book", p.7-5, a RESET signal initializes the following registers:
*
* PS = 0x0000 (which has the important side-effect of disabling interrupts and traps)
* IP = 0x0000
* CS = 0xFFFF
* DS/ES/SS = 0x0000
* PS = 0x0000 (which has the important side-effect of disabling interrupts and traps)
* IP = 0x0000
* CS = 0xFFFF
* DS/ES/SS = 0x0000
*
* It is silent as to whether the remaining registers are initialized to any particular values.
*
* According to the "80286 and 80287 Programmer's Reference Manual", these 80286 registers are reset:
*
* PS = 0x0002
* MSW = 0xFFF0
* IP = 0xFFF0
* CS Selector = 0xF000 DS/ES/SS Selector = 0x0000
* CS Base = 0xFF0000 DS/ES/SS Base = 0x000000 IDT Base = 0x000000
* CS Limit = 0xFFFF DS/ES/SS Limit = 0xFFFF IDT Limit = 0x03FF
* PS = 0x0002
* MSW = 0xFFF0
* IP = 0xFFF0
* CS Selector = 0xF000 DS/ES/SS Selector = 0x0000
* CS Base = 0xFF0000 DS/ES/SS Base = 0x000000 IDT Base = 0x000000
* CS Limit = 0xFFFF DS/ES/SS Limit = 0xFFFF IDT Limit = 0x03FF
*
* We define some additional "registers", such as regEIP. which mirrors the physical address corresponding
* to CS:IP (ie, the address of the next opcode). This means that whenever segCS or regIP are explicitly
@ -790,7 +796,7 @@ X86CPU.prototype.reset = function()
* segCS is changing (eg, undocumented 8086 opcodes), use setCS().
*
* The other segment registers (DS, SS and ES) have similar setters (for segDS, segSS and segES), but those
* functions do not mirror any special segment:offset values in the same way that regEIP mirrors CS:IP.
* functions do not mirror any segment:offset values in the same way that regEIP mirrors CS:IP.
*
* @this {X86CPU}
*/
@ -833,6 +839,37 @@ X86CPU.prototype.resetRegs = function()
this.segNULL = new X86Seg(this, X86Seg.ID.NULL, "NULL");
this.setCSIP(0, 0xFFFF); // this should be called before the first setPS() call
if (BACKTRACK) {
/*
* Initialize the backtrack indexes for all registers to zero. And while, yes, it IS possible
* for raw data to flow through segment registers as well, it's not common enough in real-mode
* (and too difficult in protected-mode) to merit the overhead. Ditto for SP, which can't really
* be considered a general-purpose register.
*
* Every time getByte() is called, btMemLo is filled with the matching backtrack info; similarly,
* every time getWord() is called, btMemLo and btMemHi are filled with the matching backtrack info
* for the low and high bytes, respectively.
*/
this.backTrack = {
btiAL: 0,
btiAH: 0,
btiBL: 0,
btiBH: 0,
btiCL: 0,
btiCH: 0,
btiDL: 0,
btiDH: 0,
btiBPLo: 0,
btiBPHi: 0,
btiSILo: 0,
btiSIHi: 0,
btiDILo: 0,
btiDIHi: 0,
btiMemLo: 0,
btiMemHi: 0
};
}
/*
* Assorted 80286-specific registers. The GDTR and IDTR registers are stored as the following pieces:
*
@ -892,7 +929,7 @@ X86CPU.prototype.resetRegs = function()
/*
* Another internal "register" we occasionally need is an interim copy of bModRM, set inside selected opcode
* handlers so that the helper function can have access to the instruction's bModRM without resorting to a closure
* (which, in Chrome's V8, for example, seems to cause constant recompilation).
* (which, in the Chrome V8 engine, for example, seems to cause constant recompilation).
*/
this.bModRM = 0;
@ -1649,8 +1686,8 @@ X86CPU.prototype.setPS = function(regPS, cpl)
* pops 0xF000 into the flags is able to set *any* of flag bits 12-15: if it can, then OS/2 declares
* the CPU an 80386. Therefore, in real-mode, we must zero all incoming bits 12-15.
*
* This has the added benefit of relieving us from having to zero the effective IOPL (this.nIOPL)
* whenever we're in real-mode, since we're zeroing the IOPL bits up front now.
* This has the added benefit of relieving us from zeroing the effective IOPL (this.nIOPL) whenever
* we're in real-mode, since we're zeroing the incoming IOPL bits up front now.
*/
if (!(this.regMSW & X86.MSW.PE)) {
regPS &= ~(X86.PS.IOPL.MASK | X86.PS.NT | X86.PS.BIT15);
@ -1735,7 +1772,7 @@ X86CPU.prototype.setBinding = function(sHTMLType, sBinding, control)
case "SS":
case "ES":
case "IP":
case "PC": // deprecated as an alias for "IP" (still used by older XML files like /disks/pc/unlisted/crobots/machine.xml)
case "PC": // deprecated as an alias for "IP" (still used by older XML files like the one at http://tpoindex.github.io/crobots/)
case "PS": // this refers to "Processor Status", aka the 16-bit flags register (DEBUG.COM actually refers to this as "PC", surprisingly)
case "C":
case "P":
@ -1765,6 +1802,9 @@ X86CPU.prototype.setBinding = function(sHTMLType, sBinding, control)
*/
X86CPU.prototype.getByte = function(addr)
{
if (BACKTRACK) {
this.backTrack.btiMemLo = this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].readBackTrack(addr & this.blockLimit);
}
return this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].readByte(addr & this.blockLimit);
};
@ -1786,8 +1826,16 @@ X86CPU.prototype.getWord = function(addr)
*/
this.nStepCycles -= this.CYCLES.nWordCyclePenalty;
if (off != this.blockLimit) {
if (BACKTRACK) {
this.backTrack.btiMemLo = this.aMemBlocks[iBlock].readBackTrack(off);
this.backTrack.btiMemHi = this.aMemBlocks[iBlock].readBackTrack(off + 1);
}
return this.aMemBlocks[iBlock].readWord(off);
}
if (BACKTRACK) {
this.backTrack.btiMemLo = this.aMemBlocks[iBlock].readBackTrack(off);
this.backTrack.btiMemHi = this.aMemBlocks[(iBlock + 1) & this.blockMask].readBackTrack(0);
}
return this.aMemBlocks[iBlock++].readByte(off) | (this.aMemBlocks[iBlock & this.blockMask].readByte(0) << 8);
};
@ -1800,6 +1848,9 @@ X86CPU.prototype.getWord = function(addr)
*/
X86CPU.prototype.setByte = function(addr, b)
{
if (BACKTRACK) {
this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].writeBackTrack(addr & this.blockLimit, this.backTrack.btiMemLo);
}
this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff);
};
@ -1821,9 +1872,17 @@ X86CPU.prototype.setWord = function(addr, w)
*/
this.nStepCycles -= this.CYCLES.nWordCyclePenalty;
if (off != this.blockLimit) {
if (BACKTRACK) {
this.aMemBlocks[iBlock].writeBackTrack(off, this.backTrack.btiMemLo);
this.aMemBlocks[iBlock].writeBackTrack(off + 1, this.backTrack.btiMemHi);
}
this.aMemBlocks[iBlock].writeWord(off, w & 0xffff);
return;
}
if (BACKTRACK) {
this.aMemBlocks[iBlock].writeBackTrack(off, this.backTrack.btiMemLo);
this.aMemBlocks[(iBlock + 1) & this.blockMask].writeBackTrack(0, this.backTrack.btiMemHi);
}
this.aMemBlocks[iBlock++].writeByte(off, w & 0xff);
this.aMemBlocks[iBlock & this.blockMask].writeByte(0, (w >> 8) & 0xff);
};
@ -2071,8 +2130,11 @@ X86CPU.prototype.getBytePrefetch = function(addr)
if (!EAFUNCS && (this.opFlags & X86.OPFLAG.NOREAD)) return 0;
var b;
if (!this.cbPrefetchQueued) {
if (MAXDEBUG) this.assert(addr == this.addrPrefetchHead, "X86CPU.getBytePrefetch(" + str.toHex(addr) + "): invalid head address (" + str.toHex(this.addrPrefetchHead) + ")");
if (MAXDEBUG) this.assert(this.iPrefetchTail == this.iPrefetchHead, "X86CPU.getBytePrefetch(" + str.toHex(addr) + "): head (" + this.iPrefetchHead + ") does not match tail (" + this.iPrefetchTail + ")");
if (MAXDEBUG) {
this.messagePrint(" getBytePrefetch[" + this.iPrefetchTail + "]: filling");
this.assert(addr == this.addrPrefetchHead, "X86CPU.getBytePrefetch(" + str.toHex(addr) + "): invalid head address (" + str.toHex(this.addrPrefetchHead) + ")");
this.assert(this.iPrefetchTail == this.iPrefetchHead, "X86CPU.getBytePrefetch(" + str.toHex(addr) + "): head (" + this.iPrefetchHead + ") does not match tail (" + this.iPrefetchTail + ")");
}
this.fillPrefetch(1);
this.nBusCycles += 4;
/*
@ -2088,8 +2150,10 @@ X86CPU.prototype.getBytePrefetch = function(addr)
*/
}
b = this.aPrefetch[this.iPrefetchTail] & 0xff;
if (MAXDEBUG) this.messagePrint(" getBytePrefetch[" + this.iPrefetchTail + "]: " + str.toHex(addr) + ":" + str.toHexByte(b));
if (MAXDEBUG) this.assert(addr == (this.aPrefetch[this.iPrefetchTail] >> 8), "X86CPU.getBytePrefetch(" + str.toHex(addr) + "): invalid tail address (" + str.toHex(this.aPrefetch[this.iPrefetchTail] >> 8) + ")");
if (MAXDEBUG) {
this.messagePrint(" getBytePrefetch[" + this.iPrefetchTail + "]: " + str.toHex(addr) + ":" + str.toHexByte(b));
this.assert(addr == (this.aPrefetch[this.iPrefetchTail] >> 8), "X86CPU.getBytePrefetch(" + str.toHex(addr) + "): invalid tail address (" + str.toHex(this.aPrefetch[this.iPrefetchTail] >> 8) + ")");
}
this.iPrefetchTail = (this.iPrefetchTail + 1) & X86CPU.PREFETCH.MASK;
this.cbPrefetchQueued--;
return b;

File diff suppressed because it is too large Load diff

View file

@ -1650,13 +1650,13 @@ var X86OpXX = {
*
* To be clear, a single assignment like this will fail:
*
* opModeRegByteF2: function(fn) {
* opModsRegByteF2: function(fn) {
* this.regDX = (this.regDX & 0xff) | (fn.call(this, this.regDX >> 8, this.regDX & 0xff) << 8);
* }
*
* which is why all affected decoders now use separate assignments; eg:
*
* opModeRegByteF2: function(fn) {
* opModsRegByteF2: function(fn) {
* var b = fn.call(this, this.regDX >> 8, this.regDX & 0xff);
* this.regDX = (this.regDX & 0xff) | (b << 8);
* }
@ -3225,7 +3225,7 @@ var X86OpXX = {
* 0xF6 0xE0: MUL AL
* 0xF6 0xE4: MUL AH
*
* because the OpModeGrpByte decoder function will attempt to put the opGrpMULb() function's
* because the OpModsGrpByte decoder function will attempt to put the opGrpMULb() function's
* return value back into AL or AH, undoing opGrpMULb's update of AX. And since opGrpMULb doesn't
* know what the target is (only the target's value), it cannot easily work around the problem.
*
@ -3251,7 +3251,7 @@ var X86OpXX = {
* 0xF7 0xE0: MUL AX
* 0xF7 0xE2: MUL DX
*
* because the OpModeGrpWord decoder function will attempt to put the opGrpMULw() function's
* because the OpModsGrpWord decoder function will attempt to put the opGrpMULw() function's
* return value back into AX or DX, undoing opGrpMULw's update of DX:AX. And since opGrpMULw doesn't
* know what the target is (only the target's value), it cannot easily work around the problem.
*

View file

@ -101,7 +101,7 @@
"./modules/pcjs/lib/messages.js",
"./modules/pcjs/lib/panel.js",
"./modules/pcjs/lib/bus.js",
"./modules/pcjs/lib/mem.js",
"./modules/pcjs/lib/memory.js",
"./modules/pcjs/lib/cpu.js",
"./modules/pcjs/lib/x86.js",
"./modules/pcjs/lib/x86seg.js",
@ -116,7 +116,7 @@
"./modules/pcjs/lib/ram.js",
"./modules/pcjs/lib/keyboard.js",
"./modules/pcjs/lib/video.js",
"./modules/pcjs/lib/serial.js",
"./modules/pcjs/lib/serialport.js",
"./modules/pcjs/lib/mouse.js",
"./modules/pcjs/lib/disk.js",
"./modules/pcjs/lib/fdc.js",