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",
|
compilation_level: "ADVANCED_OPTIMIZATIONS",
|
||||||
externs: pkg.closureCompilerExterns,
|
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",
|
warning_level: "verbose",
|
||||||
// jscomp_off: ["checkTypes", "fileoverviewTags"],
|
// jscomp_off: ["checkTypes", "fileoverviewTags"],
|
||||||
// summary_detail_level: 3,
|
// summary_detail_level: 3,
|
||||||
|
|
@ -260,7 +260,7 @@ module.exports = function(grunt) {
|
||||||
TEMPcompilerOpts: {
|
TEMPcompilerOpts: {
|
||||||
// create_source_map: "./tmp/c1pjs/" + pkg.version + "/c1p.map",
|
// create_source_map: "./tmp/c1pjs/" + pkg.version + "/c1p.map",
|
||||||
define: ["\"APPNAME='C1Pjs'\"", "\"APPVERSION='" + pkg.version + "'\"", "DEBUGGER=false",
|
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%})();//@ sourceMappingURL=/tmp/c1pjs/" + pkg.version + "/c1p.map\""
|
||||||
output_wrapper: "\"(function(){%output%})();\""
|
output_wrapper: "\"(function(){%output%})();\""
|
||||||
},
|
},
|
||||||
|
|
@ -272,7 +272,7 @@ module.exports = function(grunt) {
|
||||||
TEMPcompilerOpts: {
|
TEMPcompilerOpts: {
|
||||||
// create_source_map: "./tmp/c1pjs/" + pkg.version + "/c1p-dbg.map",
|
// create_source_map: "./tmp/c1pjs/" + pkg.version + "/c1p-dbg.map",
|
||||||
define: ["\"APPNAME='C1Pjs'\"", "\"APPVERSION='" + pkg.version + "'\"",
|
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%})();//@ sourceMappingURL=/tmp/c1pjs/" + pkg.version + "/c1p-dbg.map\""
|
||||||
output_wrapper: "\"(function(){%output%})();\""
|
output_wrapper: "\"(function(){%output%})();\""
|
||||||
},
|
},
|
||||||
|
|
@ -284,7 +284,7 @@ module.exports = function(grunt) {
|
||||||
TEMPcompilerOpts: {
|
TEMPcompilerOpts: {
|
||||||
// create_source_map: "./tmp/pcjs/" + pkg.version + "/pc.map",
|
// create_source_map: "./tmp/pcjs/" + pkg.version + "/pc.map",
|
||||||
define: ["\"APPNAME='PCjs'\"", "\"APPVERSION='" + pkg.version + "'\"", "DEBUGGER=false",
|
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%})();//@ sourceMappingURL=/tmp/pcjs/" + pkg.version + "/pc.map\""
|
||||||
output_wrapper: "\"(function(){%output%})();\""
|
output_wrapper: "\"(function(){%output%})();\""
|
||||||
},
|
},
|
||||||
|
|
@ -299,7 +299,7 @@ module.exports = function(grunt) {
|
||||||
TEMPcompilerOpts: {
|
TEMPcompilerOpts: {
|
||||||
// create_source_map: "./tmp/pcjs/" + pkg.version + "/pc-dbg.map",
|
// create_source_map: "./tmp/pcjs/" + pkg.version + "/pc-dbg.map",
|
||||||
define: ["\"APPNAME='PCjs'\"", "\"APPVERSION='" + pkg.version + "'\"",
|
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%})();//@ sourceMappingURL=/tmp/pcjs/" + pkg.version + "/pc-dbg.map\""
|
||||||
output_wrapper: "\"(function(){%output%})();\""
|
output_wrapper: "\"(function(){%output%})();\""
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -275,43 +275,52 @@ function genMode(d, w, mrm, sGroup, sRO) {
|
||||||
var sRegGet = null;
|
var sRegGet = null;
|
||||||
var sRegSet = null;
|
var sRegSet = null;
|
||||||
var sRegSetBegin = "", sRegSetEnd = "";
|
var sRegSetBegin = "", sRegSetEnd = "";
|
||||||
|
var sRegBTLo = null, sRegBTHi = null;
|
||||||
if (!w) {
|
if (!w) {
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case 0:
|
case 0:
|
||||||
sRegGet = "this.regAX & 0xff";
|
sRegGet = "this.regAX & 0xff";
|
||||||
sRegSet = "this.regAX = (this.regAX & ~0xff) | ";
|
sRegSet = "this.regAX = (this.regAX & ~0xff) | ";
|
||||||
|
sRegBTLo = "this.backTrack.btiAL";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
sRegGet = "this.regCX & 0xff";
|
sRegGet = "this.regCX & 0xff";
|
||||||
sRegSet = "this.regCX = (this.regCX & ~0xff) | ";
|
sRegSet = "this.regCX = (this.regCX & ~0xff) | ";
|
||||||
|
sRegBTLo = "this.backTrack.btiCL";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sRegGet = "this.regDX & 0xff";
|
sRegGet = "this.regDX & 0xff";
|
||||||
sRegSet = "this.regDX = (this.regDX & ~0xff) | ";
|
sRegSet = "this.regDX = (this.regDX & ~0xff) | ";
|
||||||
|
sRegBTLo = "this.backTrack.btiDL";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
sRegGet = "this.regBX & 0xff";
|
sRegGet = "this.regBX & 0xff";
|
||||||
sRegSet = "this.regBX = (this.regBX & ~0xff) | ";
|
sRegSet = "this.regBX = (this.regBX & ~0xff) | ";
|
||||||
|
sRegBTLo = "this.backTrack.btiBL";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
sRegGet = "this.regAX >> 8";
|
sRegGet = "this.regAX >> 8";
|
||||||
sRegSet = "this.regAX = (this.regAX & 0xff) | ";
|
sRegSet = "this.regAX = (this.regAX & 0xff) | ";
|
||||||
sRegSetEnd = " << 8";
|
sRegSetEnd = " << 8";
|
||||||
|
sRegBTLo = "this.backTrack.btiAH";
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
sRegGet = "this.regCX >> 8";
|
sRegGet = "this.regCX >> 8";
|
||||||
sRegSet = "this.regCX = (this.regCX & 0xff) | ";
|
sRegSet = "this.regCX = (this.regCX & 0xff) | ";
|
||||||
sRegSetEnd = " << 8";
|
sRegSetEnd = " << 8";
|
||||||
|
sRegBTLo = "this.backTrack.btiCH";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
sRegGet = "this.regDX >> 8";
|
sRegGet = "this.regDX >> 8";
|
||||||
sRegSet = "this.regDX = (this.regDX & 0xff) | ";
|
sRegSet = "this.regDX = (this.regDX & 0xff) | ";
|
||||||
sRegSetEnd = " << 8";
|
sRegSetEnd = " << 8";
|
||||||
|
sRegBTLo = "this.backTrack.btiDH";
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
sRegGet = "this.regBX >> 8";
|
sRegGet = "this.regBX >> 8";
|
||||||
sRegSet = "this.regBX = (this.regBX & 0xff) | ";
|
sRegSet = "this.regBX = (this.regBX & 0xff) | ";
|
||||||
sRegSetEnd = " << 8";
|
sRegSetEnd = " << 8";
|
||||||
|
sRegBTLo = "this.backTrack.btiBH";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sError = "unrecognized w=0 reg: " + reg;
|
sError = "unrecognized w=0 reg: " + reg;
|
||||||
|
|
@ -322,27 +331,43 @@ function genMode(d, w, mrm, sGroup, sRO) {
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case 0:
|
case 0:
|
||||||
sRegGet = "this.regAX";
|
sRegGet = "this.regAX";
|
||||||
|
sRegBTLo = "this.backTrack.btiAL";
|
||||||
|
sRegBTHi = "this.backTrack.btiAH";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
sRegGet = "this.regCX";
|
sRegGet = "this.regCX";
|
||||||
|
sRegBTLo = "this.backTrack.btiCL";
|
||||||
|
sRegBTHi = "this.backTrack.btiCH";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sRegGet = "this.regDX";
|
sRegGet = "this.regDX";
|
||||||
|
sRegBTLo = "this.backTrack.btiDL";
|
||||||
|
sRegBTHi = "this.backTrack.btiDH";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
sRegGet = "this.regBX";
|
sRegGet = "this.regBX";
|
||||||
|
sRegBTLo = "this.backTrack.btiBL";
|
||||||
|
sRegBTHi = "this.backTrack.btiBH";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
sRegGet = "this.regSP";
|
sRegGet = "this.regSP";
|
||||||
|
sRegBTLo = "X86CPU.BACKTRACK.SP_LO";
|
||||||
|
sRegBTHi = "X86CPU.BACKTRACK.SP_HI";
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
sRegGet = "this.regBP";
|
sRegGet = "this.regBP";
|
||||||
|
sRegBTLo = "this.backTrack.btiBPLo";
|
||||||
|
sRegBTHi = "this.backTrack.btiBPHi";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
sRegGet = "this.regSI";
|
sRegGet = "this.regSI";
|
||||||
|
sRegBTLo = "this.backTrack.btiSILo";
|
||||||
|
sRegBTHi = "this.backTrack.btiSIHi";
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
sRegGet = "this.regDI";
|
sRegGet = "this.regDI";
|
||||||
|
sRegBTLo = "this.backTrack.btiDILo";
|
||||||
|
sRegBTHi = "this.backTrack.btiDIHi";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sError = "unrecognized w=1 reg: " + reg;
|
sError = "unrecognized w=1 reg: " + reg;
|
||||||
|
|
@ -363,6 +388,7 @@ function genMode(d, w, mrm, sGroup, sRO) {
|
||||||
var sModRegGet = null;
|
var sModRegGet = null;
|
||||||
var sModRegSet = null;
|
var sModRegSet = null;
|
||||||
var sModRegSetBegin = "", sModRegSetEnd = "";
|
var sModRegSetBegin = "", sModRegSetEnd = "";
|
||||||
|
var sModRegBTLo = null, sModRegBTHi = null;
|
||||||
var sModRegSeg = "this.segData";
|
var sModRegSeg = "this.segData";
|
||||||
switch (mod) {
|
switch (mod) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
@ -370,44 +396,44 @@ function genMode(d, w, mrm, sGroup, sRO) {
|
||||||
case 0:
|
case 0:
|
||||||
sModAddr = "this.regBX + this.regSI";
|
sModAddr = "this.regBX + this.regSI";
|
||||||
sModFunc = "BXSI";
|
sModFunc = "BXSI";
|
||||||
nCycles = "this.nEACyclesBaseIndex"; // 8086: 7
|
nCycles = "this.CYCLES.nEACyclesBaseIndex"; // 8086: 7
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
sModAddr = "this.regBX + this.regDI";
|
sModAddr = "this.regBX + this.regDI";
|
||||||
sModFunc = "BXDI";
|
sModFunc = "BXDI";
|
||||||
nCycles = "this.nEACyclesBaseIndexExtra"; // 8086: 8
|
nCycles = "this.CYCLES.nEACyclesBaseIndexExtra"; // 8086: 8
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sModAddr = "this.regBP + this.regSI";
|
sModAddr = "this.regBP + this.regSI";
|
||||||
sModFunc = "BPSI";
|
sModFunc = "BPSI";
|
||||||
sModRegSeg = "this.segStack";
|
sModRegSeg = "this.segStack";
|
||||||
nCycles = "this.nEACyclesBaseIndexExtra"; // 8086: 8
|
nCycles = "this.CYCLES.nEACyclesBaseIndexExtra"; // 8086: 8
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
sModAddr = "this.regBP + this.regDI";
|
sModAddr = "this.regBP + this.regDI";
|
||||||
sModFunc = "BPDI";
|
sModFunc = "BPDI";
|
||||||
sModRegSeg = "this.segStack";
|
sModRegSeg = "this.segStack";
|
||||||
nCycles = "this.nEACyclesBaseIndex"; // 8086: 7
|
nCycles = "this.CYCLES.nEACyclesBaseIndex"; // 8086: 7
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
sModAddr = "this.regSI";
|
sModAddr = "this.regSI";
|
||||||
sModFunc = "SI";
|
sModFunc = "SI";
|
||||||
nCycles = "this.nEACyclesBase"; // 8086: 5
|
nCycles = "this.CYCLES.nEACyclesBase"; // 8086: 5
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
sModAddr = "this.regDI";
|
sModAddr = "this.regDI";
|
||||||
sModFunc = "DI";
|
sModFunc = "DI";
|
||||||
nCycles = "this.nEACyclesBase"; // 8086: 5
|
nCycles = "this.CYCLES.nEACyclesBase"; // 8086: 5
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
sModAddr = "this.getIPWord()";
|
sModAddr = "this.getIPWord()";
|
||||||
sModFunc = "D16";
|
sModFunc = "D16";
|
||||||
nCycles = "this.nEACyclesDisp"; // 8086: 6
|
nCycles = "this.CYCLES.nEACyclesDisp"; // 8086: 6
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
sModAddr = "this.regBX";
|
sModAddr = "this.regBX";
|
||||||
sModFunc = "BX";
|
sModFunc = "BX";
|
||||||
nCycles = "this.nEACyclesBase"; // 8086: 5
|
nCycles = "this.CYCLES.nEACyclesBase"; // 8086: 5
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sError = "unrecognized mod=0 r/m: " + r_m;
|
sError = "unrecognized mod=0 r/m: " + r_m;
|
||||||
|
|
@ -419,45 +445,45 @@ function genMode(d, w, mrm, sGroup, sRO) {
|
||||||
case 0:
|
case 0:
|
||||||
sModAddr = "this.regBX + this.regSI + this.getIPDisp()";
|
sModAddr = "this.regBX + this.regSI + this.getIPDisp()";
|
||||||
sModFunc = "BXSID8";
|
sModFunc = "BXSID8";
|
||||||
nCycles = "this.nEACyclesBaseIndexDisp"; // 8086: 11
|
nCycles = "this.CYCLES.nEACyclesBaseIndexDisp"; // 8086: 11
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
sModAddr = "this.regBX + this.regDI + this.getIPDisp()";
|
sModAddr = "this.regBX + this.regDI + this.getIPDisp()";
|
||||||
sModFunc = "BXDID8";
|
sModFunc = "BXDID8";
|
||||||
nCycles = "this.nEACyclesBaseIndexDispExtra"; // 8086: 12
|
nCycles = "this.CYCLES.nEACyclesBaseIndexDispExtra"; // 8086: 12
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sModAddr = "this.regBP + this.regSI + this.getIPDisp()";
|
sModAddr = "this.regBP + this.regSI + this.getIPDisp()";
|
||||||
sModFunc = "BPSID8";
|
sModFunc = "BPSID8";
|
||||||
sModRegSeg = "this.segStack";
|
sModRegSeg = "this.segStack";
|
||||||
nCycles = "this.nEACyclesBaseIndexDispExtra"; // 8086: 12
|
nCycles = "this.CYCLES.nEACyclesBaseIndexDispExtra"; // 8086: 12
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
sModAddr = "this.regBP + this.regDI + this.getIPDisp()";
|
sModAddr = "this.regBP + this.regDI + this.getIPDisp()";
|
||||||
sModFunc = "BPDID8";
|
sModFunc = "BPDID8";
|
||||||
sModRegSeg = "this.segStack";
|
sModRegSeg = "this.segStack";
|
||||||
nCycles = "this.nEACyclesBaseIndexDisp"; // 8086: 11
|
nCycles = "this.CYCLES.nEACyclesBaseIndexDisp"; // 8086: 11
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
sModAddr = "this.regSI + this.getIPDisp()";
|
sModAddr = "this.regSI + this.getIPDisp()";
|
||||||
sModFunc = "SID8";
|
sModFunc = "SID8";
|
||||||
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
|
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
sModAddr = "this.regDI + this.getIPDisp()";
|
sModAddr = "this.regDI + this.getIPDisp()";
|
||||||
sModFunc = "DID8";
|
sModFunc = "DID8";
|
||||||
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
|
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
sModAddr = "this.regBP + this.getIPDisp()";
|
sModAddr = "this.regBP + this.getIPDisp()";
|
||||||
sModFunc = "BPD8";
|
sModFunc = "BPD8";
|
||||||
sModRegSeg = "this.segStack";
|
sModRegSeg = "this.segStack";
|
||||||
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
|
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
sModAddr = "this.regBX + this.getIPDisp()";
|
sModAddr = "this.regBX + this.getIPDisp()";
|
||||||
sModFunc = "BXD8";
|
sModFunc = "BXD8";
|
||||||
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
|
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sError = "unrecognized mod=1 r/m: " + r_m;
|
sError = "unrecognized mod=1 r/m: " + r_m;
|
||||||
|
|
@ -469,45 +495,45 @@ function genMode(d, w, mrm, sGroup, sRO) {
|
||||||
case 0:
|
case 0:
|
||||||
sModAddr = "this.regBX + this.regSI + this.getIPWord()";
|
sModAddr = "this.regBX + this.regSI + this.getIPWord()";
|
||||||
sModFunc = "BXSID16";
|
sModFunc = "BXSID16";
|
||||||
nCycles = "this.nEACyclesBaseIndexDisp"; // 8086: 11
|
nCycles = "this.CYCLES.nEACyclesBaseIndexDisp"; // 8086: 11
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
sModAddr = "this.regBX + this.regDI + this.getIPWord()";
|
sModAddr = "this.regBX + this.regDI + this.getIPWord()";
|
||||||
sModFunc = "BXDID16";
|
sModFunc = "BXDID16";
|
||||||
nCycles = "this.nEACyclesBaseIndexDispExtra"; // 8086: 12
|
nCycles = "this.CYCLES.nEACyclesBaseIndexDispExtra"; // 8086: 12
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sModAddr = "this.regBP + this.regSI + this.getIPWord()";
|
sModAddr = "this.regBP + this.regSI + this.getIPWord()";
|
||||||
sModFunc = "BPSID16";
|
sModFunc = "BPSID16";
|
||||||
sModRegSeg = "this.segStack";
|
sModRegSeg = "this.segStack";
|
||||||
nCycles = "this.nEACyclesBaseIndexDispExtra"; // 8086: 12
|
nCycles = "this.CYCLES.nEACyclesBaseIndexDispExtra"; // 8086: 12
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
sModAddr = "this.regBP + this.regDI + this.getIPWord()";
|
sModAddr = "this.regBP + this.regDI + this.getIPWord()";
|
||||||
sModFunc = "BPDID16";
|
sModFunc = "BPDID16";
|
||||||
sModRegSeg = "this.segStack";
|
sModRegSeg = "this.segStack";
|
||||||
nCycles = "this.nEACyclesBaseIndexDisp"; // 8086: 11
|
nCycles = "this.CYCLES.nEACyclesBaseIndexDisp"; // 8086: 11
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
sModAddr = "this.regSI + this.getIPWord()";
|
sModAddr = "this.regSI + this.getIPWord()";
|
||||||
sModFunc = "SID16";
|
sModFunc = "SID16";
|
||||||
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
|
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
sModAddr = "this.regDI + this.getIPWord()";
|
sModAddr = "this.regDI + this.getIPWord()";
|
||||||
sModFunc = "DID16";
|
sModFunc = "DID16";
|
||||||
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
|
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
sModAddr = "this.regBP + this.getIPWord()";
|
sModAddr = "this.regBP + this.getIPWord()";
|
||||||
sModFunc = "BPD16";
|
sModFunc = "BPD16";
|
||||||
sModRegSeg = "this.segStack";
|
sModRegSeg = "this.segStack";
|
||||||
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
|
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
sModAddr = "this.regBX + this.getIPWord()";
|
sModAddr = "this.regBX + this.getIPWord()";
|
||||||
sModFunc = "BXD16";
|
sModFunc = "BXD16";
|
||||||
nCycles = "this.nEACyclesBaseDisp"; // 8086: 9
|
nCycles = "this.CYCLES.nEACyclesBaseDisp"; // 8086: 9
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sError = "unrecognized mod=2 r/m: " + r_m;
|
sError = "unrecognized mod=2 r/m: " + r_m;
|
||||||
|
|
@ -520,38 +546,46 @@ function genMode(d, w, mrm, sGroup, sRO) {
|
||||||
case 0:
|
case 0:
|
||||||
sModRegGet = "this.regAX & 0xff";
|
sModRegGet = "this.regAX & 0xff";
|
||||||
sModRegSet = "this.regAX = (this.regAX & ~0xff) | ";
|
sModRegSet = "this.regAX = (this.regAX & ~0xff) | ";
|
||||||
|
sModRegBTLo = "this.backTrack.btiAL";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
sModRegGet = "this.regCX & 0xff";
|
sModRegGet = "this.regCX & 0xff";
|
||||||
sModRegSet = "this.regCX = (this.regCX & ~0xff) | ";
|
sModRegSet = "this.regCX = (this.regCX & ~0xff) | ";
|
||||||
|
sModRegBTLo = "this.backTrack.btiCL";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sModRegGet = "this.regDX & 0xff";
|
sModRegGet = "this.regDX & 0xff";
|
||||||
sModRegSet = "this.regDX = (this.regDX & ~0xff) | ";
|
sModRegSet = "this.regDX = (this.regDX & ~0xff) | ";
|
||||||
|
sModRegBTLo = "this.backTrack.btiDL";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
sModRegGet = "this.regBX & 0xff";
|
sModRegGet = "this.regBX & 0xff";
|
||||||
sModRegSet = "this.regBX = (this.regBX & ~0xff) | ";
|
sModRegSet = "this.regBX = (this.regBX & ~0xff) | ";
|
||||||
|
sModRegBTLo = "this.backTrack.btiBL";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
sModRegGet = "this.regAX >> 8";
|
sModRegGet = "this.regAX >> 8";
|
||||||
sModRegSet = "this.regAX = (this.regAX & 0xff) | ";
|
sModRegSet = "this.regAX = (this.regAX & 0xff) | ";
|
||||||
sModRegSetEnd = " << 8";
|
sModRegSetEnd = " << 8";
|
||||||
|
sModRegBTLo = "this.backTrack.btiAH";
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
sModRegGet = "this.regCX >> 8";
|
sModRegGet = "this.regCX >> 8";
|
||||||
sModRegSet = "this.regCX = (this.regCX & 0xff) | ";
|
sModRegSet = "this.regCX = (this.regCX & 0xff) | ";
|
||||||
sModRegSetEnd = " << 8";
|
sModRegSetEnd = " << 8";
|
||||||
|
sModRegBTLo = "this.backTrack.btiCH";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
sModRegGet = "this.regDX >> 8";
|
sModRegGet = "this.regDX >> 8";
|
||||||
sModRegSet = "this.regDX = (this.regDX & 0xff) | ";
|
sModRegSet = "this.regDX = (this.regDX & 0xff) | ";
|
||||||
sModRegSetEnd = " << 8";
|
sModRegSetEnd = " << 8";
|
||||||
|
sModRegBTLo = "this.backTrack.btiDH";
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
sModRegGet = "this.regBX >> 8";
|
sModRegGet = "this.regBX >> 8";
|
||||||
sModRegSet = "this.regBX = (this.regBX & 0xff) | ";
|
sModRegSet = "this.regBX = (this.regBX & 0xff) | ";
|
||||||
sModRegSetEnd = " << 8";
|
sModRegSetEnd = " << 8";
|
||||||
|
sModRegBTLo = "this.backTrack.btiBH";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sError = "unrecognized w=0 mod=3 r/m: " + r_m;
|
sError = "unrecognized w=0 mod=3 r/m: " + r_m;
|
||||||
|
|
@ -562,27 +596,43 @@ function genMode(d, w, mrm, sGroup, sRO) {
|
||||||
switch (r_m) {
|
switch (r_m) {
|
||||||
case 0:
|
case 0:
|
||||||
sModRegGet = "this.regAX";
|
sModRegGet = "this.regAX";
|
||||||
|
sModRegBTLo = "this.backTrack.btiAL";
|
||||||
|
sModRegBTHi = "this.backTrack.btiAH";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
sModRegGet = "this.regCX";
|
sModRegGet = "this.regCX";
|
||||||
|
sModRegBTLo = "this.backTrack.btiCL";
|
||||||
|
sModRegBTHi = "this.backTrack.btiCH";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sModRegGet = "this.regDX";
|
sModRegGet = "this.regDX";
|
||||||
|
sModRegBTLo = "this.backTrack.btiDL";
|
||||||
|
sModRegBTHi = "this.backTrack.btiDH";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
sModRegGet = "this.regBX";
|
sModRegGet = "this.regBX";
|
||||||
|
sModRegBTLo = "this.backTrack.btiBL";
|
||||||
|
sModRegBTHi = "this.backTrack.btiBH";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
sModRegGet = "this.regSP";
|
sModRegGet = "this.regSP";
|
||||||
|
sModRegBTLo = "X86CPU.BACKTRACK.SP_LO";
|
||||||
|
sModRegBTHi = "X86CPU.BACKTRACK.SP_HI";
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
sModRegGet = "this.regBP";
|
sModRegGet = "this.regBP";
|
||||||
|
sModRegBTLo = "this.backTrack.btiBPLo";
|
||||||
|
sModRegBTHi = "this.backTrack.btiBPHi";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
sModRegGet = "this.regSI";
|
sModRegGet = "this.regSI";
|
||||||
|
sModRegBTLo = "this.backTrack.btiSILo";
|
||||||
|
sModRegBTHi = "this.backTrack.btiSIHi";
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
sModRegGet = "this.regDI";
|
sModRegGet = "this.regDI";
|
||||||
|
sModRegBTLo = "this.backTrack.btiDILo";
|
||||||
|
sModRegBTHi = "this.backTrack.btiDIHi";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sError = "unrecognized w=1 mod=3 r/m: " + r_m;
|
sError = "unrecognized w=1 mod=3 r/m: " + r_m;
|
||||||
|
|
@ -614,17 +664,18 @@ function genMode(d, w, mrm, sGroup, sRO) {
|
||||||
}
|
}
|
||||||
|
|
||||||
print(" /**");
|
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(" * @this {X86CPU}");
|
||||||
print(" * @param {Array.<function(number,number)>} afnGrp");
|
print(" * @param {Array.<function(number,number)>} afnGrp");
|
||||||
print(" * @param {function()} fnSrc");
|
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(" */");
|
||||||
print(" " + sOpMod + ": function(afnGrp, fnSrc) {");
|
print(" " + sOpMod + ": function(afnGrp, fnSrc) {");
|
||||||
|
|
||||||
if (sModAddr) {
|
if (sModAddr) {
|
||||||
if (sModAddr.indexOf("+") > 0)
|
if (sModAddr.indexOf("+") > 0) {
|
||||||
sModAddr = "((" + sModAddr + ") & 0xffff)";
|
sModAddr = "((" + sModAddr + ") & 0xffff)";
|
||||||
|
}
|
||||||
if (!d) {
|
if (!d) {
|
||||||
if (reg == 7 && sRO) {
|
if (reg == 7 && sRO) {
|
||||||
if (sModFunc) {
|
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(" var " + sTemp + " = afnGrp[" + reg + "].call(this, " + sModRegGet + ", fnSrc.call(this));");
|
||||||
print(" " + sModRegSet + sModRegSetBegin + sTemp + sModRegSetEnd + ";");
|
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(" /**");
|
||||||
|
print(" * " + sOpMod + "(fn): mod=" + toMod(d, mod) + " reg=" + toReg(d, w, reg) + " r/m=" + toRM(mod, w, r_m));
|
||||||
|
print(" *");
|
||||||
print(" * @this {X86CPU}");
|
print(" * @this {X86CPU}");
|
||||||
print(" * @param {function(number,number)} fn (dst,src)");
|
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(" */");
|
||||||
print(" " + sOpMod + ": function(fn) {");
|
print(" " + sOpMod + ": function(fn) {");
|
||||||
|
|
||||||
if (sModAddr && sRegGet) {
|
if (sModAddr && sRegGet) {
|
||||||
|
|
||||||
if (sModAddr.indexOf("+") > 0)
|
if (sModAddr.indexOf("+") > 0) {
|
||||||
sModAddr = "((" + sModAddr + ") & 0xffff)";
|
sModAddr = "((" + sModAddr + ") & 0xffff)";
|
||||||
|
}
|
||||||
if (!d) {
|
if (!d) {
|
||||||
if (sModFunc) {
|
if (sModFunc) {
|
||||||
if (fInline) {
|
if (fInline) {
|
||||||
print(" var " + sTemp + " = fn.call(this, this.modEA" + aSize[w] + "(" + sModRegSeg + ", " + sModAddr + "), " + sRegGet + ");");
|
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 + ");");
|
print(" this.setEA" + aSize[w] + "(" + sTemp + ");");
|
||||||
} else {
|
} else {
|
||||||
sModFunc = "write" + sModFunc + aSize[w];
|
sModFunc = "write" + sModFunc + aSize[w];
|
||||||
|
|
@ -723,6 +793,15 @@ function genMode(d, w, mrm, sGroup, sRO) {
|
||||||
} else {
|
} else {
|
||||||
print(" this.regEAWrite = " + sModRegSeg + "[1] + " + sModAddr + ";");
|
print(" this.regEAWrite = " + sModRegSeg + "[1] + " + sModAddr + ";");
|
||||||
print(" var " + sTemp + " = fn.call(this, this.modEA" + aSize[w] + "(this.regEAWrite), " + sRegGet + ");");
|
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 + ");");
|
print(" this.setEA" + aSize[w] + "(this.regEAWrite, " + sTemp + ");");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -763,6 +842,15 @@ function genMode(d, w, mrm, sGroup, sRO) {
|
||||||
print(" " + sRegSet + sRegSetBegin + sTemp + sRegSetEnd + ";");
|
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)
|
if (nCycles !== null)
|
||||||
print(" this.nStepCycles -= " + nCycles + ";");
|
print(" this.nStepCycles -= " + nCycles + ";");
|
||||||
|
|
@ -783,6 +871,15 @@ function genMode(d, w, mrm, sGroup, sRO) {
|
||||||
print(" var " + sTemp + " = fn.call(this, " + sModRegGet + ", " + sRegGet + ");");
|
print(" var " + sTemp + " = fn.call(this, " + sModRegGet + ", " + sRegGet + ");");
|
||||||
print(" " + sModRegSet + sModRegSetBegin + sTemp + sModRegSetEnd + ";");
|
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 {
|
else {
|
||||||
if (!sRegSet) {
|
if (!sRegSet) {
|
||||||
|
|
@ -799,6 +896,15 @@ function genMode(d, w, mrm, sGroup, sRO) {
|
||||||
print(" var " + sTemp + " = fn.call(this, " + sRegGet + ", " + sModRegGet + ");");
|
print(" var " + sTemp + " = fn.call(this, " + sRegGet + ", " + sModRegGet + ");");
|
||||||
print(" " + sRegSet + sRegSetBegin + sTemp + sRegSetEnd + ";");
|
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
|
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)).
|
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"
|
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),
|
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)
|
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/weblib.js](../../shared/lib/weblib.js)
|
||||||
* [shared/component.js](../../shared/lib/component.js)
|
* [shared/component.js](../../shared/lib/component.js)
|
||||||
* [pcjs/defines.js](defines.js)
|
* [pcjs/defines.js](defines.js)
|
||||||
|
* [pcjs/interrupts.js](interrupts.js)
|
||||||
|
* [pcjs/messages.js](messages.js)
|
||||||
* [pcjs/panel.js](panel.js)
|
* [pcjs/panel.js](panel.js)
|
||||||
* [pcjs/bus.js](bus.js)
|
* [pcjs/bus.js](bus.js)
|
||||||
* [pcjs/mem.js](mem.js)
|
* [pcjs/memory.js](memory.js)
|
||||||
* [pcjs/cpu.js](cpu.js)
|
* [pcjs/cpu.js](cpu.js)
|
||||||
* [pcjs/x86.js](x86.js)
|
* [pcjs/x86.js](x86.js)
|
||||||
* [pcjs/x86seg.js](x86seg.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/x86grps.js](x86grps.js)
|
||||||
* [pcjs/x86help.js](x86help.js)
|
* [pcjs/x86help.js](x86help.js)
|
||||||
* [pcjs/x86mods.js](x86mods.js)
|
* [pcjs/x86mods.js](x86mods.js)
|
||||||
* [pcjs/x86op0f.js](x86op0f.js)
|
|
||||||
* [pcjs/x86opxx.js](x86opxx.js)
|
* [pcjs/x86opxx.js](x86opxx.js)
|
||||||
|
* [pcjs/x86op0f.js](x86op0f.js)
|
||||||
* [pcjs/chipset.js](chipset.js)
|
* [pcjs/chipset.js](chipset.js)
|
||||||
* [pcjs/rom.js](rom.js)
|
* [pcjs/rom.js](rom.js)
|
||||||
* [pcjs/ram.js](ram.js)
|
* [pcjs/ram.js](ram.js)
|
||||||
* [pcjs/keyboard.js](keyboard.js)
|
* [pcjs/keyboard.js](keyboard.js)
|
||||||
* [pcjs/video.js](video.js)
|
* [pcjs/video.js](video.js)
|
||||||
* [pcjs/serial.js](serial.js)
|
* [pcjs/serialport.js](serialport.js)
|
||||||
* [pcjs/mouse.js](mouse.js)
|
* [pcjs/mouse.js](mouse.js)
|
||||||
* [pcjs/disk.js](disk.js)
|
* [pcjs/disk.js](disk.js)
|
||||||
* [pcjs/fdc.js](fdc.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
|
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
|
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.
|
[*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') {
|
if (typeof module !== 'undefined') {
|
||||||
var str = require("../../shared/lib/strlib");
|
var str = require("../../shared/lib/strlib");
|
||||||
var Component = require("../../shared/lib/component");
|
var Component = require("../../shared/lib/component");
|
||||||
var Memory = require("./mem");
|
var Memory = require("./memory");
|
||||||
var State = require("./state");
|
var State = require("./state");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class BackTrack
|
||||||
|
* @property {Object} obj
|
||||||
|
* @property {number} off
|
||||||
|
* @property {number} slot
|
||||||
|
* @property {number} refs
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bus(cpu, dbg)
|
* Bus(cpu, dbg)
|
||||||
*
|
*
|
||||||
|
|
@ -154,11 +162,36 @@ function Bus(parmsBus, cpu, dbg)
|
||||||
* Allocate empty Memory blocks to span the entire physical address space.
|
* Allocate empty Memory blocks to span the entire physical address space.
|
||||||
*/
|
*/
|
||||||
this.initMemory();
|
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();
|
this.setReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.subclass(Component, Bus);
|
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()
|
* initMemory()
|
||||||
*
|
*
|
||||||
|
|
@ -431,6 +464,80 @@ Bus.prototype.setWordDirect = function(addr, w)
|
||||||
this.aMemBlocks[iBlock & this.blockMask].writeByteDirect(0, (w >> 8) & 0xff);
|
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()
|
* saveMemory()
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -2747,6 +2747,7 @@ ChipSet.prototype.requestDMA = function(iDMAChannel, done)
|
||||||
/**
|
/**
|
||||||
* advanceDMA(channel, fInit)
|
* advanceDMA(channel, fInit)
|
||||||
*
|
*
|
||||||
|
* @this {ChipSet}
|
||||||
* @param {Object} channel
|
* @param {Object} channel
|
||||||
* @param {boolean} [fInit]
|
* @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
|
* 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().
|
* requiring any special assistance from the CPU via setDMA().
|
||||||
*/
|
*/
|
||||||
var obj = this;
|
var bto = null;
|
||||||
|
var chipset = this;
|
||||||
var fAsyncRequest = false;
|
var fAsyncRequest = false;
|
||||||
var controller = channel.controller;
|
var controller = channel.controller;
|
||||||
var iDMAChannel = controller.nChannelBase + channel.iChannel;
|
var iDMAChannel = controller.nChannelBase + channel.iChannel;
|
||||||
|
|
@ -2791,11 +2793,11 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
|
||||||
if (channel.xfer == ChipSet.DMA_MODE.XFER_WRITE) {
|
if (channel.xfer == ChipSet.DMA_MODE.XFER_WRITE) {
|
||||||
fAsyncRequest = true;
|
fAsyncRequest = true;
|
||||||
(function advanceDMAWrite(addrCur) {
|
(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 (b < 0) {
|
||||||
if (!channel.fWarning) {
|
if (!channel.fWarning) {
|
||||||
if (DEBUG && obj.messageEnabled(Messages.DMA)) {
|
if (DEBUG && chipset.messageEnabled(Messages.DMA)) {
|
||||||
obj.messagePrint("advanceDMA(" + iDMAChannel + ") ran out of data, assuming 0xff", true);
|
chipset.messagePrint("advanceDMA(" + iDMAChannel + ") ran out of data, assuming 0xff", true);
|
||||||
}
|
}
|
||||||
channel.fWarning = true;
|
channel.fWarning = true;
|
||||||
}
|
}
|
||||||
|
|
@ -2807,18 +2809,20 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
|
||||||
if (!channel.masked) {
|
if (!channel.masked) {
|
||||||
/*
|
/*
|
||||||
* While it makes sense to call bus.setByteDirect(), since DMA deals with physical memory,
|
* 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.
|
* 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;
|
fAsyncRequest = fAsync;
|
||||||
if (fAsync) {
|
if (fAsync) {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
if (!obj.updateDMA(channel)) {
|
if (!chipset.updateDMA(channel)) chipset.advanceDMA(channel);
|
||||||
obj.advanceDMA(channel);
|
|
||||||
}
|
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -2827,12 +2831,12 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
|
||||||
else if (channel.xfer == ChipSet.DMA_MODE.XFER_READ) {
|
else if (channel.xfer == ChipSet.DMA_MODE.XFER_READ) {
|
||||||
/*
|
/*
|
||||||
* While it makes sense to call bus.getByteDirect(), since DMA deals with physical memory,
|
* 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),
|
* TODO: Determine whether we should support async dmaWrite() functions (currently not required),
|
||||||
* and consider providing a Bus memory interface that honors read breakpoints.
|
* 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) {
|
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,
|
* 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)
|
* updateDMA(channel)
|
||||||
*
|
*
|
||||||
|
* @this {ChipSet}
|
||||||
* @param {Object} channel
|
* @param {Object} channel
|
||||||
* @return {boolean} true if DMA operation complete, false if not
|
* @return {boolean} true if DMA operation complete, false if not
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,19 @@ var TYPEDARRAYS = false; // (typeof ArrayBuffer !== 'undefined');
|
||||||
/**
|
/**
|
||||||
* @define {boolean}
|
* @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;
|
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
|
* 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
|
* 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
|
* 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
|
* 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.
|
* 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
|
* 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.
|
* 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.
|
* 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
|
* 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.
|
* 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
|
* 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
|
* "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.
|
* 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
|
* 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.
|
* of the new 'data' array of dwords) and converting them on-the-fly to the current format.
|
||||||
*/
|
*/
|
||||||
this.nCylinders = aDiskData.length;
|
this.nCylinders = aDiskData.length;
|
||||||
this.nHeads = aDiskData[0].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
|
* 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
|
* 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
|
* isn't even aware of the extent of the transfer, so in the case of a read request, all readByte() can do is return
|
||||||
* until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted.
|
* 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.
|
* 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:
|
* The following drive properties must have been setup prior to our first call:
|
||||||
*
|
*
|
||||||
|
|
@ -2301,16 +2301,21 @@ FDC.prototype.doFormat = function(drive)
|
||||||
*
|
*
|
||||||
* @this {FDC}
|
* @this {FDC}
|
||||||
* @param {Object} drive
|
* @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)
|
FDC.prototype.readByte = function(drive, done)
|
||||||
{
|
{
|
||||||
var b = -1;
|
var b = -1;
|
||||||
|
var obj, off; // these variables are purely for BACKTRACK purposes
|
||||||
|
|
||||||
if (!drive.resCode && drive.disk) {
|
if (!drive.resCode && drive.disk) {
|
||||||
do {
|
do {
|
||||||
if (drive.sector) {
|
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;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Locate the next sector, and then try reading again.
|
* Locate the next sector, and then try reading again.
|
||||||
|
|
@ -2328,7 +2333,7 @@ FDC.prototype.readByte = function(drive, done)
|
||||||
this.advanceSector(drive);
|
this.advanceSector(drive);
|
||||||
} while (true);
|
} 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 {boolean} [fReadOnly] is true if the block must be marked read-only
|
||||||
* @param {Object} [controller] is an optional memory controller component
|
* @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.cb = size || 0;
|
||||||
this.adw = null;
|
this.adw = null;
|
||||||
this.offset = 0;
|
this.offset = 0;
|
||||||
|
|
@ -109,6 +112,18 @@ function Memory(addr, size, fReadOnly, controller) {
|
||||||
this.controller = null;
|
this.controller = null;
|
||||||
this.fDirty = this.fDirtyEver = false;
|
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
|
* For empty memory blocks, all we need to do is ensure all access functions
|
||||||
* are mapped to "none" handlers.
|
* 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;
|
* 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)
|
* 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.
|
* 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) {
|
if (TYPEDARRAYS) {
|
||||||
this.buffer = new ArrayBuffer(size);
|
this.buffer = new ArrayBuffer(size);
|
||||||
|
|
@ -149,216 +167,307 @@ function Memory(addr, size, fReadOnly, controller) {
|
||||||
if (FATARRAYS) {
|
if (FATARRAYS) {
|
||||||
this.ab = new Array(size);
|
this.ab = new Array(size);
|
||||||
} else {
|
} 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);
|
this.adw = new Array(size >> 2);
|
||||||
for (var i = 0; i < this.adw.length; i++) {
|
for (i = 0; i < this.adw.length; i++) this.adw[i] = 0;
|
||||||
this.adw[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.setAccess(Memory.afnMemory);
|
this.setAccess(Memory.afnMemory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory.prototype = {
|
/**
|
||||||
constructor: Memory,
|
* readNone(off)
|
||||||
/**
|
*
|
||||||
* readNone(off)
|
* @this {Memory}
|
||||||
*
|
* @param {number} off
|
||||||
* @this {Memory}
|
* @return {number}
|
||||||
* @param {number} off
|
*/
|
||||||
* @return {number}
|
Memory.readNone = function readNone(off)
|
||||||
*/
|
{
|
||||||
readNone: function(off) {
|
if (DEBUGGER && this.dbg.messageEnabled(Messages.MEM) /* && !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));
|
||||||
this.dbg.message("attempt to read invalid block %" + str.toHex(this.addr) + " from " + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel));
|
}
|
||||||
}
|
return 0;
|
||||||
return 0;
|
};
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
* writeNone(off, v)
|
* writeNone(off, v)
|
||||||
*
|
*
|
||||||
* @this {Memory}
|
* @this {Memory}
|
||||||
* @param {number} off
|
* @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)
|
* @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) {
|
Memory.writeNone = function writeNone(off, v) {
|
||||||
if (DEBUGGER && this.dbg.messageEnabled(Messages.MEM) /* && !off */) {
|
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);
|
this.dbg.message("attempt to write 0x" + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* readByteMemory(off)
|
/**
|
||||||
*
|
* readByteMemory(off)
|
||||||
* @this {Memory}
|
*
|
||||||
* @param {number} off
|
* @this {Memory}
|
||||||
* @return {number}
|
* @param {number} off
|
||||||
*/
|
* @return {number}
|
||||||
readByteMemory: function readByteMemory(off) {
|
*/
|
||||||
Component.assert(off >= 0 && off < this.cb);
|
Memory.readByteMemory = function readByteMemory(off)
|
||||||
if (FATARRAYS) {
|
{
|
||||||
return this.ab[off];
|
Component.assert(off >= 0 && off < this.cb);
|
||||||
}
|
if (FATARRAYS) {
|
||||||
return ((this.adw[off >> 2] >>> ((off & 0x3) << 3)) & 0xff);
|
return this.ab[off];
|
||||||
},
|
}
|
||||||
/**
|
return ((this.adw[off >> 2] >>> ((off & 0x3) << 3)) & 0xff);
|
||||||
* readWordMemory(off)
|
};
|
||||||
*
|
|
||||||
* @this {Memory}
|
/**
|
||||||
* @param {number} off
|
* readWordMemory(off)
|
||||||
* @return {number}
|
*
|
||||||
*/
|
* @this {Memory}
|
||||||
readWordMemory: function readWordMemory(off) {
|
* @param {number} off
|
||||||
Component.assert(off >= 0 && off < this.cb - 1);
|
* @return {number}
|
||||||
if (FATARRAYS) {
|
*/
|
||||||
return this.ab[off] | (this.ab[off + 1] << 8);
|
Memory.readWordMemory = function readWordMemory(off)
|
||||||
}
|
{
|
||||||
var w;
|
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 idw = off >> 2;
|
||||||
var nShift = (off & 0x3) << 3;
|
var nShift = (off & 0x3) << 3;
|
||||||
var dw = (this.adw[idw] >>> nShift);
|
|
||||||
if (nShift < 24) {
|
if (nShift < 24) {
|
||||||
w = dw & 0xffff;
|
this.adw[idw] = (this.adw[idw] & ~(0xffff << nShift)) | (w << nShift);
|
||||||
} else {
|
} 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;
|
}
|
||||||
},
|
this.fDirty = true;
|
||||||
/**
|
};
|
||||||
* writeByteMemory(off, b)
|
|
||||||
*
|
/**
|
||||||
* @this {Memory}
|
* readByteChecked(off)
|
||||||
* @param {number} off
|
*
|
||||||
* @param {number} b
|
* @this {Memory}
|
||||||
*/
|
* @param {number} off
|
||||||
writeByteMemory: function writeByteMemory(off, b) {
|
* @return {number}
|
||||||
Component.assert(off >= 0 && off < this.cb && (b & 0xff) == b);
|
*/
|
||||||
if (FATARRAYS) {
|
Memory.readByteChecked = function readByteChecked(off)
|
||||||
this.ab[off] = b;
|
{
|
||||||
} else {
|
if (DEBUGGER) this.dbg.checkMemoryRead(this.addr + off);
|
||||||
var idw = off >> 2;
|
return this.readByteDirect(off);
|
||||||
var nShift = (off & 0x3) << 3;
|
};
|
||||||
this.adw[idw] = (this.adw[idw] & ~(0xff << nShift)) | (b << nShift);
|
|
||||||
}
|
/**
|
||||||
this.fDirty = true;
|
* readWordChecked(off)
|
||||||
},
|
*
|
||||||
/**
|
* @this {Memory}
|
||||||
* writeWordMemory(off, w)
|
* @param {number} off
|
||||||
*
|
* @return {number}
|
||||||
* @this {Memory}
|
*/
|
||||||
* @param {number} off
|
Memory.readWordChecked = function readWordChecked(off)
|
||||||
* @param {number} w
|
{
|
||||||
*/
|
if (DEBUGGER) {
|
||||||
writeWordMemory: function writeWordMemory(off, w) {
|
this.dbg.checkMemoryRead(this.addr + off) || this.dbg.checkMemoryRead(this.addr + off + 1); // jshint ignore:line
|
||||||
Component.assert(off >= 0 && off < this.cb - 1 && (w & 0xffff) == w);
|
}
|
||||||
if (FATARRAYS) {
|
return this.readWordDirect(off);
|
||||||
this.ab[off] = (w & 0xff);
|
};
|
||||||
this.ab[off + 1] = (w >> 8);
|
|
||||||
} else {
|
/**
|
||||||
var idw = off >> 2;
|
* writeByteChecked(off, b)
|
||||||
var nShift = (off & 0x3) << 3;
|
*
|
||||||
if (nShift < 24) {
|
* @this {Memory}
|
||||||
this.adw[idw] = (this.adw[idw] & ~(0xffff << nShift)) | (w << nShift);
|
* @param {number} off
|
||||||
} else {
|
* @param {number} b
|
||||||
this.adw[idw] = (this.adw[idw] & 0x00ffffff) | (w << 24);
|
*/
|
||||||
idw++;
|
Memory.writeByteChecked = function writeByteChecked(off, b)
|
||||||
this.adw[idw] = (this.adw[idw] & 0xffffff00) | (w >> 8);
|
{
|
||||||
}
|
if (DEBUGGER) this.dbg.checkMemoryWrite(this.addr + off);
|
||||||
}
|
this.writeByteDirect(off, b);
|
||||||
this.fDirty = true;
|
};
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
* readByteChecked(off)
|
* writeWordChecked(off, w)
|
||||||
*
|
*
|
||||||
* @this {Memory}
|
* @this {Memory}
|
||||||
* @param {number} off
|
* @param {number} off
|
||||||
* @return {number}
|
* @param {number} w
|
||||||
*/
|
*/
|
||||||
readByteChecked: function readByteChecked(off) {
|
Memory.writeWordChecked = function writeWordChecked(off, w)
|
||||||
if (DEBUGGER) this.dbg.checkMemoryRead(this.addr + off);
|
{
|
||||||
return this.readByteDirect(off);
|
if (DEBUGGER) {
|
||||||
},
|
this.dbg.checkMemoryWrite(this.addr + off) || this.dbg.checkMemoryWrite(this.addr + off + 1); // jshint ignore:line
|
||||||
/**
|
}
|
||||||
* readWordChecked(off)
|
this.writeWordDirect(off, w);
|
||||||
*
|
};
|
||||||
* @this {Memory}
|
|
||||||
* @param {number} off
|
/**
|
||||||
* @return {number}
|
* readByteTypedArray(off)
|
||||||
*/
|
*
|
||||||
readWordChecked: function readWordChecked(off) {
|
* @this {Memory}
|
||||||
if (DEBUGGER) {
|
* @param {number} off
|
||||||
this.dbg.checkMemoryRead(this.addr + off) || this.dbg.checkMemoryRead(this.addr + off + 1); // jshint ignore:line
|
* @return {number}
|
||||||
}
|
*/
|
||||||
return this.readWordDirect(off);
|
Memory.readByteTypedArray = function readByteTypedArray(off)
|
||||||
},
|
{
|
||||||
/**
|
Component.assert(off >= 0 && off < this.cb);
|
||||||
* writeByteChecked(off, b)
|
return this.ab[off];
|
||||||
*
|
};
|
||||||
* @this {Memory}
|
|
||||||
* @param {number} off
|
/**
|
||||||
* @param {number} b
|
* readWordTypedArray(off)
|
||||||
*/
|
*
|
||||||
writeByteChecked: function writeByteChecked(off, b) {
|
* @this {Memory}
|
||||||
if (DEBUGGER) this.dbg.checkMemoryWrite(this.addr + off);
|
* @param {number} off
|
||||||
this.writeByteDirect(off, b);
|
* @return {number}
|
||||||
},
|
*/
|
||||||
/**
|
Memory.readWordTypedArray = function readWordTypedArray(off)
|
||||||
* writeWordChecked(off, w)
|
{
|
||||||
*
|
Component.assert(off >= 0 && off < this.cb - 1);
|
||||||
* @this {Memory}
|
return this.dv.getUint16(off, true);
|
||||||
* @param {number} off
|
};
|
||||||
* @param {number} w
|
|
||||||
*/
|
/**
|
||||||
writeWordChecked: function writeWordChecked(off, w) {
|
* writeByteTypedArray(off, b)
|
||||||
if (DEBUGGER) {
|
*
|
||||||
this.dbg.checkMemoryWrite(this.addr + off) || this.dbg.checkMemoryWrite(this.addr + off + 1); // jshint ignore:line
|
* @this {Memory}
|
||||||
}
|
* @param {number} off
|
||||||
this.writeWordDirect(off, w);
|
* @param {number} b
|
||||||
},
|
*/
|
||||||
/**
|
Memory.writeByteTypedArray = function writeByteTypedArray(off, b)
|
||||||
* readByteTypedArray(off)
|
{
|
||||||
*
|
Component.assert(off >= 0 && off < this.cb && (b & 0xff) == b);
|
||||||
* @this {Memory}
|
this.ab[off] = b;
|
||||||
* @param {number} off
|
this.fDirty = true;
|
||||||
* @return {number}
|
};
|
||||||
*/
|
|
||||||
readByteTypedArray: function readByteTypedArray(off) {
|
/**
|
||||||
Component.assert(off >= 0 && off < this.cb);
|
* writeWordTypedArray(off, w)
|
||||||
return this.ab[off];
|
*
|
||||||
},
|
* @this {Memory}
|
||||||
/**
|
* @param {number} off
|
||||||
* readWordTypedArray(off)
|
* @param {number} w
|
||||||
*
|
*/
|
||||||
* @this {Memory}
|
Memory.writeWordTypedArray = function writeWordTypedArray(off, w)
|
||||||
* @param {number} off
|
{
|
||||||
* @return {number}
|
Component.assert(off >= 0 && off < this.cb - 1 && (w & 0xffff) == w);
|
||||||
*/
|
this.dv.setUint16(off, w, true);
|
||||||
readWordTypedArray: function readWordTypedArray(off) {
|
this.fDirty = true;
|
||||||
Component.assert(off >= 0 && off < this.cb - 1);
|
};
|
||||||
return this.dv.getUint16(off, true);
|
|
||||||
},
|
/**
|
||||||
/**
|
* readBackTrackNone(off)
|
||||||
* writeByteTypedArray(off, b)
|
*
|
||||||
*
|
* @this {Memory}
|
||||||
* @this {Memory}
|
* @param {number} off
|
||||||
* @param {number} off
|
* @return {number}
|
||||||
* @param {number} b
|
*/
|
||||||
*/
|
Memory.readBackTrackNone = function readBackTrackNone(off)
|
||||||
writeByteTypedArray: function writeByteTypedArray(off, b) {
|
{
|
||||||
Component.assert(off >= 0 && off < this.cb && (b & 0xff) == b);
|
return 0;
|
||||||
this.ab[off] = b;
|
};
|
||||||
this.fDirty = true;
|
|
||||||
},
|
/**
|
||||||
/**
|
* writeBackTrackNone(off, bti)
|
||||||
* writeWordTypedArray(off, w)
|
*
|
||||||
*
|
* @this {Memory}
|
||||||
* @this {Memory}
|
* @param {number} off
|
||||||
* @param {number} off
|
* @param {number} bti
|
||||||
* @param {number} w
|
*/
|
||||||
*/
|
Memory.writeBackTrackNone = function writeBackTrackNone(off, bti)
|
||||||
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;
|
/**
|
||||||
},
|
* 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()
|
* 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,
|
* 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
|
* 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
|
* 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
|
* memory blocks installed at the programmed address, and so we arrived here at a block with
|
||||||
* controller AND no data.
|
* no controller AND no data.
|
||||||
*/
|
*/
|
||||||
Component.assert(adw != null);
|
Component.assert(adw != null);
|
||||||
if (adw && this.cb == adw.length << 2) {
|
if (adw && this.cb == adw.length << 2) {
|
||||||
|
|
@ -473,11 +582,11 @@ Memory.prototype = {
|
||||||
* @param {boolean} [fDirect]
|
* @param {boolean} [fDirect]
|
||||||
*/
|
*/
|
||||||
setReadAccess: function(afn, fDirect) {
|
setReadAccess: function(afn, fDirect) {
|
||||||
this.readByte = afn[0]? afn[0] : this.readNone;
|
this.readByte = afn[0] || Memory.readNone;
|
||||||
this.readWord = afn[1]? afn[1] : this.readNone;
|
this.readWord = afn[1] || Memory.readNone;
|
||||||
if (fDirect) {
|
if (fDirect) {
|
||||||
this.readByteDirect = afn[0]? afn[0] : this.readNone;
|
this.readByteDirect = afn[0] || Memory.readNone;
|
||||||
this.readWordDirect = afn[1]? afn[1] : this.readNone;
|
this.readWordDirect = afn[1] || Memory.readNone;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
|
@ -488,11 +597,11 @@ Memory.prototype = {
|
||||||
* @param {boolean} [fDirect]
|
* @param {boolean} [fDirect]
|
||||||
*/
|
*/
|
||||||
setWriteAccess: function(afn, fDirect) {
|
setWriteAccess: function(afn, fDirect) {
|
||||||
this.writeByte = afn[2] && !this.fReadOnly? afn[2] : this.writeNone;
|
this.writeByte = !this.fReadOnly && afn[2] || Memory.writeNone;
|
||||||
this.writeWord = afn[3] && !this.fReadOnly? afn[3] : this.writeNone;
|
this.writeWord = !this.fReadOnly && afn[3] || Memory.writeNone;
|
||||||
if (fDirect) {
|
if (fDirect) {
|
||||||
this.writeByteDirect = afn[2]? afn[2] : this.writeNone;
|
this.writeByteDirect = afn[2] || Memory.writeNone;
|
||||||
this.writeWordDirect = afn[3]? afn[3] : this.writeNone;
|
this.writeWordDirect = afn[3] || Memory.writeNone;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
|
@ -510,8 +619,8 @@ Memory.prototype = {
|
||||||
* @this {Memory}
|
* @this {Memory}
|
||||||
*/
|
*/
|
||||||
resetWriteAccess: function() {
|
resetWriteAccess: function() {
|
||||||
this.writeByte = this.fReadOnly? this.writeNone : this.writeByteDirect;
|
this.writeByte = this.fReadOnly? Memory.writeNone : this.writeByteDirect;
|
||||||
this.writeWord = this.fReadOnly? this.writeNone : this.writeWordDirect;
|
this.writeWord = this.fReadOnly? Memory.writeNone : this.writeWordDirect;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* setDebugInfo(cpu, dbg, addr, size)
|
* 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 APP_PCJS !== 'undefined') APP_PCJS.Memory = Memory;
|
||||||
|
|
||||||
if (typeof module !== 'undefined') module.exports = Memory;
|
if (typeof module !== 'undefined') module.exports = Memory;
|
||||||
|
|
@ -37,7 +37,7 @@ if (typeof module !== 'undefined') {
|
||||||
var web = require("../../shared/lib/weblib");
|
var web = require("../../shared/lib/weblib");
|
||||||
var Component = require("../../shared/lib/component");
|
var Component = require("../../shared/lib/component");
|
||||||
var Messages = require("./messages");
|
var Messages = require("./messages");
|
||||||
var SerialPort = require("./serial");
|
var SerialPort = require("./serialport");
|
||||||
var State = require("./state");
|
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
|
* 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.
|
* found in the original IBM PC ROM BIOS listing. TODO: Fill in remaining RBDA holes.
|
||||||
*
|
|
||||||
* TODO: Fill in remaining RBDA holes.
|
|
||||||
*/
|
*/
|
||||||
ROM.BIOS = {};
|
ROM.BIOS = {
|
||||||
ROM.BIOS.RS232_BASE = 0x400; // 4 (word) I/O addresses of RS-232 adapters
|
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
|
PRINTER_BASE: 0x408, // 4 (word) I/O addresses of printer adapters
|
||||||
ROM.BIOS.EQUIP_FLAG = 0x410; // installed hardware (word)
|
EQUIP_FLAG: 0x410, // installed hardware (word)
|
||||||
ROM.BIOS.MFG_TEST = 0x412; // initialization flag (byte)
|
MFG_TEST: 0x412, // initialization flag (byte)
|
||||||
ROM.BIOS.MEMORY_SIZE = 0x413; // memory size in K-bytes (word)
|
MEMORY_SIZE: 0x413, // memory size in K-bytes (word)
|
||||||
ROM.BIOS.RESET_FLAG = 0x472; // set to 0x1234 if keyboard reset underway (word)
|
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
|
};
|
||||||
|
|
||||||
// RESET_FLAG is the traditional end of the RBDA, as originally defined at real-mode segment 0x40.
|
// 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
|
* 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.
|
* 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 (addr == null) return true;
|
||||||
if (this.bus.addMemory(addr, this.sizeROM, 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)");
|
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++) {
|
for (var i = 0; i < this.abROM.length; i++) {
|
||||||
this.bus.setByteDirect(addr + i, this.abROM[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;
|
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.
|
* 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
|
* 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
|
* change the value of the memory, we will not set fDirty. The default write functions in memory.js don't take
|
||||||
* performance hit, but here, it may be worthwhile, because if it results in fewer dirty blocks, display updates
|
* that performance hit, but here, it may be worthwhile, because if it results in fewer dirty blocks, display
|
||||||
* may be faster.
|
* updates may be faster.
|
||||||
*
|
*
|
||||||
* Note that we don't have to worry about dealing with word accesses that straddle block boundaries, because
|
* 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
|
* 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
|
* 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.
|
* (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 = {};
|
if (BACKTRACK) {
|
||||||
X86CPU.PREFETCH.QUEUE = 4;
|
X86CPU.BACKTRACK = {
|
||||||
X86CPU.PREFETCH.ARRAY = 8; // smallest power-of-two > PREFETCH.QUEUE
|
SP_LO: 0,
|
||||||
X86CPU.PREFETCH.MASK = 0x7; // (X86CPU.PREFETCH.ARRAY - 1)
|
SP_HI: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* initMemory(aMemBlocks, addrLimit, blockShift, blockLimit, blockMask)
|
* 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.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.aOpGrp4b = X86Grps.aOpGrp4b.slice();
|
||||||
this.aOpGrp4w = X86Grps.aOpGrp4w.slice();
|
this.aOpGrp4w = X86Grps.aOpGrp4w.slice();
|
||||||
this.aOpGrp6 = X86Op0F.aOpGrp6Real; // setProtMode() will ensure that aOpGrp6 is switched
|
this.aOpGrp6 = X86Op0F.aOpGrp6Real; // setProtMode() will ensure that aOpGrp6 is switched
|
||||||
|
|
@ -754,7 +761,6 @@ X86CPU.prototype.reset = function()
|
||||||
this.resetRegs();
|
this.resetRegs();
|
||||||
this.resetCycles();
|
this.resetCycles();
|
||||||
this.clearError(); // clear any fatal error/exception that setError() may have flagged
|
this.clearError(); // clear any fatal error/exception that setError() may have flagged
|
||||||
|
|
||||||
if (SAMPLER) {
|
if (SAMPLER) {
|
||||||
this.iSampleNext = 0;
|
this.iSampleNext = 0;
|
||||||
this.iSampleFreq = 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:
|
* 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)
|
* PS = 0x0000 (which has the important side-effect of disabling interrupts and traps)
|
||||||
* IP = 0x0000
|
* IP = 0x0000
|
||||||
* CS = 0xFFFF
|
* CS = 0xFFFF
|
||||||
* DS/ES/SS = 0x0000
|
* DS/ES/SS = 0x0000
|
||||||
*
|
*
|
||||||
* It is silent as to whether the remaining registers are initialized to any particular values.
|
* 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:
|
* According to the "80286 and 80287 Programmer's Reference Manual", these 80286 registers are reset:
|
||||||
*
|
*
|
||||||
* PS = 0x0002
|
* PS = 0x0002
|
||||||
* MSW = 0xFFF0
|
* MSW = 0xFFF0
|
||||||
* IP = 0xFFF0
|
* IP = 0xFFF0
|
||||||
* CS Selector = 0xF000 DS/ES/SS Selector = 0x0000
|
* CS Selector = 0xF000 DS/ES/SS Selector = 0x0000
|
||||||
* CS Base = 0xFF0000 DS/ES/SS Base = 0x000000 IDT Base = 0x000000
|
* CS Base = 0xFF0000 DS/ES/SS Base = 0x000000 IDT Base = 0x000000
|
||||||
* CS Limit = 0xFFFF DS/ES/SS Limit = 0xFFFF IDT Limit = 0x03FF
|
* 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
|
* 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
|
* 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().
|
* 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
|
* 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}
|
* @this {X86CPU}
|
||||||
*/
|
*/
|
||||||
|
|
@ -833,6 +839,37 @@ X86CPU.prototype.resetRegs = function()
|
||||||
this.segNULL = new X86Seg(this, X86Seg.ID.NULL, "NULL");
|
this.segNULL = new X86Seg(this, X86Seg.ID.NULL, "NULL");
|
||||||
this.setCSIP(0, 0xFFFF); // this should be called before the first setPS() call
|
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:
|
* 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
|
* 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
|
* 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;
|
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
|
* 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.
|
* 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)
|
* This has the added benefit of relieving us from zeroing the effective IOPL (this.nIOPL) whenever
|
||||||
* whenever we're in real-mode, since we're zeroing the IOPL bits up front now.
|
* we're in real-mode, since we're zeroing the incoming IOPL bits up front now.
|
||||||
*/
|
*/
|
||||||
if (!(this.regMSW & X86.MSW.PE)) {
|
if (!(this.regMSW & X86.MSW.PE)) {
|
||||||
regPS &= ~(X86.PS.IOPL.MASK | X86.PS.NT | X86.PS.BIT15);
|
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 "SS":
|
||||||
case "ES":
|
case "ES":
|
||||||
case "IP":
|
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 "PS": // this refers to "Processor Status", aka the 16-bit flags register (DEBUG.COM actually refers to this as "PC", surprisingly)
|
||||||
case "C":
|
case "C":
|
||||||
case "P":
|
case "P":
|
||||||
|
|
@ -1765,6 +1802,9 @@ X86CPU.prototype.setBinding = function(sHTMLType, sBinding, control)
|
||||||
*/
|
*/
|
||||||
X86CPU.prototype.getByte = function(addr)
|
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);
|
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;
|
this.nStepCycles -= this.CYCLES.nWordCyclePenalty;
|
||||||
if (off != this.blockLimit) {
|
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);
|
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);
|
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)
|
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);
|
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;
|
this.nStepCycles -= this.CYCLES.nWordCyclePenalty;
|
||||||
if (off != this.blockLimit) {
|
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);
|
this.aMemBlocks[iBlock].writeWord(off, w & 0xffff);
|
||||||
return;
|
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++].writeByte(off, w & 0xff);
|
||||||
this.aMemBlocks[iBlock & this.blockMask].writeByte(0, (w >> 8) & 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;
|
if (!EAFUNCS && (this.opFlags & X86.OPFLAG.NOREAD)) return 0;
|
||||||
var b;
|
var b;
|
||||||
if (!this.cbPrefetchQueued) {
|
if (!this.cbPrefetchQueued) {
|
||||||
if (MAXDEBUG) this.assert(addr == this.addrPrefetchHead, "X86CPU.getBytePrefetch(" + str.toHex(addr) + "): invalid head address (" + str.toHex(this.addrPrefetchHead) + ")");
|
if (MAXDEBUG) {
|
||||||
if (MAXDEBUG) this.assert(this.iPrefetchTail == this.iPrefetchHead, "X86CPU.getBytePrefetch(" + str.toHex(addr) + "): head (" + this.iPrefetchHead + ") does not match tail (" + this.iPrefetchTail + ")");
|
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.fillPrefetch(1);
|
||||||
this.nBusCycles += 4;
|
this.nBusCycles += 4;
|
||||||
/*
|
/*
|
||||||
|
|
@ -2088,8 +2150,10 @@ X86CPU.prototype.getBytePrefetch = function(addr)
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
b = this.aPrefetch[this.iPrefetchTail] & 0xff;
|
b = this.aPrefetch[this.iPrefetchTail] & 0xff;
|
||||||
if (MAXDEBUG) this.messagePrint(" getBytePrefetch[" + this.iPrefetchTail + "]: " + str.toHex(addr) + ":" + str.toHexByte(b));
|
if (MAXDEBUG) {
|
||||||
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) + ")");
|
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.iPrefetchTail = (this.iPrefetchTail + 1) & X86CPU.PREFETCH.MASK;
|
||||||
this.cbPrefetchQueued--;
|
this.cbPrefetchQueued--;
|
||||||
return b;
|
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:
|
* 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);
|
* 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:
|
* 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);
|
* var b = fn.call(this, this.regDX >> 8, this.regDX & 0xff);
|
||||||
* this.regDX = (this.regDX & 0xff) | (b << 8);
|
* this.regDX = (this.regDX & 0xff) | (b << 8);
|
||||||
* }
|
* }
|
||||||
|
|
@ -3225,7 +3225,7 @@ var X86OpXX = {
|
||||||
* 0xF6 0xE0: MUL AL
|
* 0xF6 0xE0: MUL AL
|
||||||
* 0xF6 0xE4: MUL AH
|
* 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
|
* 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.
|
* 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 0xE0: MUL AX
|
||||||
* 0xF7 0xE2: MUL DX
|
* 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
|
* 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.
|
* 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/messages.js",
|
||||||
"./modules/pcjs/lib/panel.js",
|
"./modules/pcjs/lib/panel.js",
|
||||||
"./modules/pcjs/lib/bus.js",
|
"./modules/pcjs/lib/bus.js",
|
||||||
"./modules/pcjs/lib/mem.js",
|
"./modules/pcjs/lib/memory.js",
|
||||||
"./modules/pcjs/lib/cpu.js",
|
"./modules/pcjs/lib/cpu.js",
|
||||||
"./modules/pcjs/lib/x86.js",
|
"./modules/pcjs/lib/x86.js",
|
||||||
"./modules/pcjs/lib/x86seg.js",
|
"./modules/pcjs/lib/x86seg.js",
|
||||||
|
|
@ -116,7 +116,7 @@
|
||||||
"./modules/pcjs/lib/ram.js",
|
"./modules/pcjs/lib/ram.js",
|
||||||
"./modules/pcjs/lib/keyboard.js",
|
"./modules/pcjs/lib/keyboard.js",
|
||||||
"./modules/pcjs/lib/video.js",
|
"./modules/pcjs/lib/video.js",
|
||||||
"./modules/pcjs/lib/serial.js",
|
"./modules/pcjs/lib/serialport.js",
|
||||||
"./modules/pcjs/lib/mouse.js",
|
"./modules/pcjs/lib/mouse.js",
|
||||||
"./modules/pcjs/lib/disk.js",
|
"./modules/pcjs/lib/disk.js",
|
||||||
"./modules/pcjs/lib/fdc.js",
|
"./modules/pcjs/lib/fdc.js",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue