Groundwork laid for upcoming BACKTRACK support
This commit is contained in:
parent
359672e2ff
commit
2034428e9f
17 changed files with 5524 additions and 3147 deletions
10
Gruntfile.js
10
Gruntfile.js
|
|
@ -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%})();\""
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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(" }");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in a new issue