Simplified flag management

This commit is contained in:
Jeff Parsons 2016-04-21 15:41:58 -07:00
commit 425f565b11
7 changed files with 443 additions and 382 deletions

View file

@ -71,25 +71,7 @@ var CPUDef = {
SF: 0x0080, // bit 7: Sign flag
ALL: 0x00D5, // CF, PF, AF, ZF, SF
MASK: 0x00FF, //
IF: 0x0200, // bit 9: Interrupt flag (for internal use only)
OF: 0x0800 // bit 11: Overflow flag (for internal use only)
},
RESULT: {
/*
* Flags are computed using the following internal registers:
*
* CF: resultZeroCarry & resultSize (ie, 0x100 or 0x10000)
* PF: resultParitySign & 0xff
* AF: (resultParitySign ^ resultAuxOverflow) & 0x0010
* ZF: resultZeroCarry & (resultSize - 1)
* SF: resultParitySign & (resultSize >> 1)
* OF: (resultParitySign ^ resultAuxOverflow ^ (resultParitySign >> 1)) & (resultSize >> 1)
*/
SIZE_BYTE: 0x00100, // mask for byte arithmetic instructions (after subtracting 1)
SIZE_WORD: 0x10000, // mask for word arithmetic instructions (after subtracting 1)
AUXOVF_AF: 0x00010,
AUXOVF_OF: 0x08080,
AUXOVF_CF: 0x10100
IF: 0x0200 // bit 9: Interrupt flag (for internal use only)
},
PARITY: [ // 256-byte array with a 1 wherever the number of set bits of the array index is EVEN
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
@ -132,10 +114,6 @@ var CPUDef = {
ACI: 0xCE, // PS.ALL
CALL: 0xCD
// to be continued....
},
CYCLES: {
ACI: 7 // 2 cycles, 7 states
// to be continued....
}
};
@ -148,7 +126,7 @@ CPUDef.PS.DIRECT = (CPUDef.PS.IF);
* However, PS "arithmetic" flags are NOT stored in regPS; they are maintained across
* separate result registers, hence the "indirect" designation.
*/
CPUDef.PS.INDIRECT = (CPUDef.PS.CF | CPUDef.PS.PF | CPUDef.PS.AF | CPUDef.PS.ZF | CPUDef.PS.SF | CPUDef.PS.OF);
CPUDef.PS.INDIRECT = (CPUDef.PS.CF | CPUDef.PS.PF | CPUDef.PS.AF | CPUDef.PS.ZF | CPUDef.PS.SF);
/*
* These are the default "always set" PS bits for the 8080.

View file

@ -55,11 +55,102 @@ CPUDef.opNOP = function()
*/
CPUDef.opLXIB = function()
{
this.regC = this.getPCByte();
this.regB = this.getPCByte();
this.setBC(this.getPCWord());
this.nStepCycles -= 10;
};
/**
* op=0x02 (STAX B)
*
* @this {CPUSim}
*/
CPUDef.opSTAXB = function()
{
this.setByte(this.getBC(), this.regA);
this.nStepCycles -= 7;
};
/**
* op=0x03 (INX B)
*
* @this {CPUSim}
*/
CPUDef.opINXB = function()
{
this.setBC(this.getBC() + 1);
this.nStepCycles -= 5;
};
/**
* op=0x04 (INR B)
*
* @this {CPUSim}
*/
CPUDef.opINRB = function()
{
this.regB = this.incByte(this.regB);
this.nStepCycles -= 5;
};
/**
* op=0x05 (DCR B)
*
* @this {CPUSim}
*/
CPUDef.opDCRB = function()
{
this.regB = this.decByte(this.regB);
this.nStepCycles -= 5;
};
/**
* op=0x06 (MVI B,d8)
*
* @this {CPUSim}
*/
CPUDef.opMVIB = function()
{
this.regB = this.getPCByte();
this.nStepCycles -= 7;
};
/**
* op=0x07 (RLC)
*
* @this {CPUSim}
*/
CPUDef.opRLC = function()
{
var b = this.regA << 1;
this.regA = (b & 0xff) | (b >> 8);
this.resultZeroCarry = (this.resultZeroCarry & 0xff) | (b & 0x100);
this.nStepCycles -= 4;
};
/**
* op=0x09 (DAD B)
*
* @this {CPUSim}
*/
CPUDef.opDADB = function()
{
var w;
this.setHL(w = this.getHL() + this.getBC());
this.resultZeroCarry = (this.resultZeroCarry & 0xff) | ((w >> 8) & 0x100);
this.nStepCycles -= 10;
};
/**
* op=0x0A (LDAX B)
*
* @this {CPUSim}
*/
CPUDef.opLDAXB = function()
{
this.regA = this.getByte(this.getBC());
this.nStepCycles -= 7;
};
/**
* opTBD()
*
@ -80,9 +171,9 @@ CPUDef.opTBD = function()
* money on array lookup.
*/
CPUDef.aOps = [
/* 0x00-0x03 */ CPUDef.opNOP, CPUDef.opLXIB, CPUDef.opTBD, CPUDef.opTBD,
/* 0x04-0x07 */ CPUDef.opTBD, CPUDef.opTBD, CPUDef.opTBD, CPUDef.opTBD,
/* 0x08-0x0B */ CPUDef.opTBD, CPUDef.opTBD, CPUDef.opTBD, CPUDef.opTBD,
/* 0x00-0x03 */ CPUDef.opNOP, CPUDef.opLXIB, CPUDef.opSTAXB, CPUDef.opINXB,
/* 0x04-0x07 */ CPUDef.opINRB, CPUDef.opDCRB, CPUDef.opMVIB, CPUDef.opRLC,
/* 0x08-0x0B */ CPUDef.opNOP, CPUDef.opDADB, CPUDef.opLDAXB, CPUDef.opTBD,
/* 0x0C-0x0F */ CPUDef.opTBD, CPUDef.opTBD, CPUDef.opTBD, CPUDef.opTBD,
/* 0x10-0x13 */ CPUDef.opTBD, CPUDef.opTBD, CPUDef.opTBD, CPUDef.opTBD,
/* 0x14-0x17 */ CPUDef.opTBD, CPUDef.opTBD, CPUDef.opTBD, CPUDef.opTBD,

View file

@ -212,7 +212,6 @@ CPUSim.prototype.removeMemCheck = function(addr, fWrite)
*/
CPUSim.prototype.initProcessor = function()
{
this.cycleCounts = CPUDef.CYCLES;
this.aOps = CPUDef.aOps;
};
@ -323,37 +322,113 @@ CPUSim.prototype.restore = function(data)
};
/**
* getPC()
* setBinding(sHTMLType, sBinding, control, sValue)
*
* @this {CPUSim}
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "AX")
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
* @param {string} [sValue] optional data value
* @return {boolean} true if binding was successful, false if unrecognized binding request
*/
CPUSim.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
{
var fBound = false;
switch (sBinding) {
case "A":
case "B":
case "C":
case "D":
case "E":
case "H":
case "L":
case "SP":
case "PC":
case "F":
case "CF":
case "PF":
case "AF":
case "ZF":
case "SF":
case "VF":
this.bindings[sBinding] = control;
this.cLiveRegs++;
fBound = true;
break;
default:
fBound = this.parent.setBinding.call(this, sHTMLType, sBinding, control);
break;
}
return fBound;
};
/**
* getBC()
*
* @this {CPUSim}
* @return {number}
*/
CPUSim.prototype.getPC = function()
CPUSim.prototype.getBC = function()
{
return this.regPC;
return (this.regB << 8) | this.regC;
};
/**
* setPC(off)
* setBC(w)
*
* @this {CPUSim}
* @param {number} off
* @param {number} w
*/
CPUSim.prototype.setPC = function(off)
CPUSim.prototype.setBC = function(w)
{
this.regPC = off & 0xffff;
this.regB = (w >> 8) & 0xff;
this.regC = w & 0xff;
};
/**
* checkPC(inc)
* getDE()
*
* @this {CPUSim}
* @param {number} inc (positive)
* @return {number} new PC
* @return {number}
*/
CPUSim.prototype.checkPC = function(inc)
CPUSim.prototype.getDE = function()
{
return (this.regPC + inc)|0;
return (this.regD << 8) | this.regE;
};
/**
* setDE(w)
*
* @this {CPUSim}
* @param {number} w
*/
CPUSim.prototype.setDE = function(w)
{
this.regD = (w >> 8) & 0xff;
this.regE = w & 0xff;
};
/**
* getHL()
*
* @this {CPUSim}
* @return {number}
*/
CPUSim.prototype.getHL = function()
{
return (this.regH << 8) | this.regL;
};
/**
* setHL(w)
*
* @this {CPUSim}
* @param {number} w
*/
CPUSim.prototype.setHL = function(w)
{
this.regH = (w >> 8) & 0xff;
this.regL = w & 0xff;
};
/**
@ -379,14 +454,25 @@ CPUSim.prototype.setSP = function(off)
};
/**
* getCarry()
* getPC()
*
* @this {CPUSim}
* @return {number} 0 or 1, depending on whether CF is clear or set
* @return {number}
*/
CPUSim.prototype.getCarry = function()
CPUSim.prototype.getPC = function()
{
return this.getCF()? 1 : 0;
return this.regPC;
};
/**
* setPC(off)
*
* @this {CPUSim}
* @param {number} off
*/
CPUSim.prototype.setPC = function(off)
{
this.regPC = off & 0xffff;
};
/**
@ -397,7 +483,7 @@ CPUSim.prototype.getCarry = function()
*/
CPUSim.prototype.getCF = function()
{
return (this.resultValue & this.resultSize)? CPUDef.PS.CF : 0;
return (this.resultZeroCarry & 0x100)? CPUDef.PS.CF : 0;
};
/**
@ -419,7 +505,7 @@ CPUSim.prototype.getPF = function()
*/
CPUSim.prototype.getAF = function()
{
return ((this.resultParitySign ^ this.resultAuxOverflow) & CPUDef.RESULT.AUXOVF_AF)? CPUDef.PS.AF : 0;
return ((this.resultParitySign ^ this.resultAuxOverflow) & 0x10)? CPUDef.PS.AF : 0;
};
/**
@ -430,7 +516,7 @@ CPUSim.prototype.getAF = function()
*/
CPUSim.prototype.getZF = function()
{
return (this.resultValue & (this.resultSize - 1))? 0 : CPUDef.PS.ZF;
return (this.resultZeroCarry & 0xff)? 0 : CPUDef.PS.ZF;
};
/**
@ -441,7 +527,7 @@ CPUSim.prototype.getZF = function()
*/
CPUSim.prototype.getSF = function()
{
return (this.resultParitySign & (this.resultSize >> 1))? CPUDef.PS.SF : 0;
return (this.resultParitySign & 0x80)? CPUDef.PS.SF : 0;
};
/**
@ -455,17 +541,6 @@ CPUSim.prototype.getIF = function()
return (this.regPS & CPUDef.PS.IF);
};
/**
* getOF()
*
* @this {CPUSim}
* @return {number} 0 or CPUDef.PS.OF
*/
CPUSim.prototype.getOF = function()
{
return ((this.resultParitySign ^ this.resultAuxOverflow ^ (this.resultParitySign >> 1)) & (this.resultSize >> 1))? CPUDef.PS.OF : 0;
};
/**
* clearCF()
*
@ -473,7 +548,7 @@ CPUSim.prototype.getOF = function()
*/
CPUSim.prototype.clearCF = function()
{
this.resultValue &= ~this.resultSize;
this.resultZeroCarry &= 0xff;
};
/**
@ -493,7 +568,7 @@ CPUSim.prototype.clearPF = function()
*/
CPUSim.prototype.clearAF = function()
{
this.resultAuxOverflow = (this.resultParitySign & CPUDef.RESULT.AUXOVF_AF) | (this.resultAuxOverflow & ~CPUDef.RESULT.AUXOVF_AF);
this.resultAuxOverflow = (this.resultParitySign & 0x10) | (this.resultAuxOverflow & ~0x10);
};
/**
@ -503,7 +578,7 @@ CPUSim.prototype.clearAF = function()
*/
CPUSim.prototype.clearZF = function()
{
this.resultValue |= (this.resultSize - 1);
this.resultZeroCarry |= 0xff;
};
/**
@ -513,10 +588,7 @@ CPUSim.prototype.clearZF = function()
*/
CPUSim.prototype.clearSF = function()
{
if (this.getSF()) {
this.resultParitySign ^= (this.resultSize >> 1) | (this.resultSize >> 2);
this.resultAuxOverflow ^= CPUDef.RESULT.AUXOVF_OF;
}
if (this.getSF()) this.resultParitySign ^= 0xc0;
};
/**
@ -529,17 +601,6 @@ CPUSim.prototype.clearIF = function()
this.regPS &= ~CPUDef.PS.IF;
};
/**
* clearOF()
*
* @this {CPUSim}
*/
CPUSim.prototype.clearOF = function()
{
this.resultParitySign &= ~this.resultSize;
this.resultAuxOverflow = (this.resultParitySign & CPUDef.RESULT.AUXOVF_OF) | (this.resultAuxOverflow & ~CPUDef.RESULT.AUXOVF_OF);
};
/**
* setCF()
*
@ -547,7 +608,7 @@ CPUSim.prototype.clearOF = function()
*/
CPUSim.prototype.setCF = function()
{
this.resultValue |= this.resultSize;
this.resultZeroCarry |= 0x100;
};
/**
@ -567,7 +628,7 @@ CPUSim.prototype.setPF = function()
*/
CPUSim.prototype.setAF = function()
{
this.resultAuxOverflow = ~(this.resultParitySign & CPUDef.RESULT.AUXOVF_AF) & CPUDef.RESULT.AUXOVF_AF | (this.resultAuxOverflow & ~CPUDef.RESULT.AUXOVF_AF);
this.resultAuxOverflow = (~this.resultParitySign & 0x10) | (this.resultAuxOverflow & ~0x10);
};
/**
@ -577,7 +638,7 @@ CPUSim.prototype.setAF = function()
*/
CPUSim.prototype.setZF = function()
{
this.resultValue &= ~(this.resultSize - 1);
this.resultZeroCarry &= ~0xff;
};
/**
@ -587,10 +648,7 @@ CPUSim.prototype.setZF = function()
*/
CPUSim.prototype.setSF = function()
{
if (!this.getSF()) {
this.resultParitySign ^= (this.resultSize >> 1) | (this.resultSize >> 2);
this.resultAuxOverflow ^= CPUDef.RESULT.AUXOVF_OF;
}
if (!this.getSF()) this.resultParitySign ^= 0xc0;
};
/**
@ -603,17 +661,6 @@ CPUSim.prototype.setIF = function()
this.regPS |= CPUDef.PS.IF;
};
/**
* setOF()
*
* @this {CPUSim}
*/
CPUSim.prototype.setOF = function()
{
this.resultParitySign |= this.resultSize;
this.resultAuxOverflow = (this.resultParitySign & CPUDef.RESULT.AUXOVF_OF) | (this.resultAuxOverflow & ~CPUDef.RESULT.AUXOVF_OF);
};
/**
* getPS()
*
@ -622,7 +669,7 @@ CPUSim.prototype.setOF = function()
*/
CPUSim.prototype.getPS = function()
{
return (this.regPS & ~CPUDef.PS.INDIRECT) | (this.getCF() | this.getPF() | this.getAF() | this.getZF() | this.getSF());
return (this.regPS & ~CPUDef.PS.INDIRECT) | (this.getSF() | this.getZF() | this.getAF() | this.getPF() | this.getCF());
};
/**
@ -630,82 +677,52 @@ CPUSim.prototype.getPS = function()
*
* @this {CPUSim}
* @param {number} regPS
* @param {number} [cpl]
*/
CPUSim.prototype.setPS = function(regPS, cpl)
CPUSim.prototype.setPS = function(regPS)
{
this.resultSize = CPUDef.RESULT.SIZE_BYTE;
this.resultValue = this.resultParitySign = this.resultAuxOverflow = 0;
if (regPS & CPUDef.PS.CF) {
this.setCF();
}
if (!(regPS & CPUDef.PS.PF)) {
this.resultParitySign |= 0x1;
}
if (regPS & CPUDef.PS.AF) {
this.resultAuxOverflow |= CPUDef.RESULT.AUXOVF_AF;
}
if (!(regPS & CPUDef.PS.ZF)) {
this.clearZF();
}
if (regPS & CPUDef.PS.SF) {
this.setSF();
}
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = 0;
if (regPS & CPUDef.PS.CF) this.resultZeroCarry |= 0x100;
if (!(regPS & CPUDef.PS.PF)) this.resultParitySign |= 0x01;
if (regPS & CPUDef.PS.AF) this.resultAuxOverflow |= 0x10;
if (!(regPS & CPUDef.PS.ZF)) this.resultZeroCarry |= 0xff;
if (regPS & CPUDef.PS.SF) this.resultParitySign ^= 0xc0;
this.regPS = (this.regPS & ~CPUDef.PS.DIRECT) | (regPS & CPUDef.PS.DIRECT) | CPUDef.PS.SET;
/*
* Assert that all requested flag bits now agree with our simulated (PS_INDIRECT) bits
*/
Component.assert((regPS & CPUDef.PS.INDIRECT) == (this.getPS() & CPUDef.PS.INDIRECT));
};
/**
* setBinding(sHTMLType, sBinding, control, sValue)
* incByte(b)
*
* @this {CPUSim}
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "AX")
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
* @param {string} [sValue] optional data value
* @return {boolean} true if binding was successful, false if unrecognized binding request
* @param {number} b
* @return {number}
*/
CPUSim.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
CPUSim.prototype.incByte = function(b)
{
var fBound = false;
switch (sBinding) {
case "A":
case "B":
case "C":
case "D":
case "E":
case "H":
case "L":
case "SP":
case "PC":
case "F":
case "C":
case "P":
case "A":
case "Z":
case "S":
case "V":
this.bindings[sBinding] = control;
this.cLiveRegs++;
fBound = true;
break;
default:
fBound = this.parent.setBinding.call(this, sHTMLType, sBinding, control);
break;
}
return fBound;
this.resultAuxOverflow = b;
b = (this.resultParitySign = b + 1) & 0xff;
this.resultZeroCarry = (this.resultZeroCarry & ~0xff) | b;
return b;
};
/**
* decByte(b)
*
* @this {CPUSim}
* @param {number} b
* @return {number}
*/
CPUSim.prototype.decByte = function(b)
{
this.resultAuxOverflow = b;
b = (this.resultParitySign = b - 1) & 0xff;
this.resultZeroCarry = (this.resultZeroCarry & ~0xff) | b;
return b;
};
/**
* getByte(addr)
*
* Use bus.getByte() for physical addresses, and cpu.getByte() for linear addresses; the latter takes care
* of cycle counts, if any.
*
* @this {CPUSim}
* @param {number} addr is a linear address
* @return {number} byte (8-bit) value at that address
@ -773,9 +790,8 @@ CPUSim.prototype.setWord = function(addr, w)
*/
CPUSim.prototype.getPCByte = function()
{
var newPC = this.checkPC(1);
var b = this.getByte(this.regPC);
this.regPC = newPC;
this.setPC(this.regPC + 1);
return b;
};
@ -787,37 +803,11 @@ CPUSim.prototype.getPCByte = function()
*/
CPUSim.prototype.getPCWord = function()
{
var newPC = this.checkPC(2);
var w = this.getWord(this.regPC);
this.regPC = newPC;
this.setPC(this.regPC + 2);
return w;
};
/**
* getPCDisp()
*
* @this {CPUSim}
* @return {number} sign-extended (32-bit) value from the byte at the current PC; PC advanced by 1
*/
CPUSim.prototype.getPCDisp = function()
{
var newPC = this.checkPC(1);
var w = ((this.getByte(this.regPC)) << 24) >> 24;
this.regPC = newPC;
return w;
};
/**
* peekPCByte()
*
* @this {CPUSim}
* @return {number} byte at the current PC
*/
CPUSim.prototype.peekPCByte = function()
{
return this.getByte(this.regPC);
};
/**
* popWord()
*

View file

@ -165,7 +165,7 @@ function parseXML(sXML, sXMLFile, idMachine, sAppClass, sParms, fResolve, displa
if (!fResolve) {
/*
* I'm trying to switch to a shared components.xsl (at least for all PC-class machines),
* but in the interim, that means hacking the XSL file on the fly to reflect the chosen class.
* but in the interim, that means hacking the XSL file on the fly to reflect the actual class.
*/
sXML = sXML.replace(/(<xsl:variable name="APPCLASS">).*?(<\/xsl:variable>)/, "$1" + sAppClass + "$2");