Cleaned up the handling of PS bits (not to be confused with PSW, which is PS combined with A); this fixes a bug where POP PSW was inadvertently disabling the internal interrupt flag (IF)

This commit is contained in:
Jeff Parsons 2016-05-05 13:04:46 -07:00
commit c80f22e23a
6 changed files with 203 additions and 170 deletions

View file

@ -69,7 +69,7 @@ var CPUDef = {
BIT5: 0x0020, // bit 5: reserved, always clear
ZF: 0x0040, // bit 6: Zero flag
SF: 0x0080, // bit 7: Sign flag
ALL: 0x00D5, // CF, PF, AF, ZF, SF
ALL: 0x00D5, // all "arithmetic" flags (CF, PF, AF, ZF, SF)
MASK: 0x00FF, //
IF: 0x0200 // bit 9: Interrupt flag (for internal use only)
},
@ -113,18 +113,19 @@ var CPUDef = {
};
/*
* Some PS flags are stored directly in regPS, hence the "direct" designation.
* These are the internal PS bits (outside of PS.MASK) that getPS() and setPS() can get and set,
* but which cannot be seen with any of the documented instructions.
*/
CPUDef.PS.DIRECT = (CPUDef.PS.IF);
CPUDef.PS.INTERNAL = (CPUDef.PS.IF);
/*
* However, PS "arithmetic" flags are NOT stored in regPS; they are maintained across
* separate result registers, hence the "indirect" designation.
* PS "arithmetic" flags are NOT stored in regPS; they are maintained across separate result registers,
* hence the RESULT designation.
*/
CPUDef.PS.INDIRECT = (CPUDef.PS.CF | CPUDef.PS.PF | CPUDef.PS.AF | CPUDef.PS.ZF | CPUDef.PS.SF);
CPUDef.PS.RESULT = (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.
* These are the "always set" PS bits for the 8080.
*/
CPUDef.PS.SET = (CPUDef.PS.BIT1);

View file

@ -2703,9 +2703,7 @@ CPUDef.opRP = function()
*/
CPUDef.opPOPSW = function()
{
var w = this.popWord();
this.setPS(w);
this.regA = w >> 8;
this.setPSW(this.popWord());
this.nStepCycles -= 10;
};
@ -2755,7 +2753,7 @@ CPUDef.opCP = function()
*/
CPUDef.opPUPSW = function()
{
this.pushWord((this.getPS() & 0xff) | (this.regA << 8));
this.pushWord(this.getPSW());
this.nStepCycles -= 11;
};

View file

@ -162,8 +162,7 @@ CPUSim.prototype.resetRegs = function()
this.setPC(this.addrReset);
/*
* This resets the Processor Status flags (regPS), along with all the internal "result registers";
* we've taken care to ensure that both CPL and IOPL are initialized before this first setPS() call.
* This resets the Processor Status flags (regPS), along with all the internal "result registers".
*/
this.setPS(0);
@ -415,6 +414,16 @@ CPUSim.prototype.setPC = function(off)
this.regPC = off & 0xffff;
};
/**
* clearCF()
*
* @this {CPUSim}
*/
CPUSim.prototype.clearCF = function()
{
this.resultZeroCarry &= 0xff;
};
/**
* getCF()
*
@ -426,121 +435,6 @@ CPUSim.prototype.getCF = function()
return (this.resultZeroCarry & 0x100)? CPUDef.PS.CF : 0;
};
/**
* getPF()
*
* @this {CPUSim}
* @return {number} 0 or CPUDef.PS.PF
*/
CPUSim.prototype.getPF = function()
{
return (CPUDef.PARITY[this.resultParitySign & 0xff])? CPUDef.PS.PF : 0;
};
/**
* getAF()
*
* @this {CPUSim}
* @return {number} 0 or CPUDef.PS.AF
*/
CPUSim.prototype.getAF = function()
{
return ((this.resultParitySign ^ this.resultAuxOverflow) & 0x10)? CPUDef.PS.AF : 0;
};
/**
* getZF()
*
* @this {CPUSim}
* @return {number} 0 or CPUDef.PS.ZF
*/
CPUSim.prototype.getZF = function()
{
return (this.resultZeroCarry & 0xff)? 0 : CPUDef.PS.ZF;
};
/**
* getSF()
*
* @this {CPUSim}
* @return {number} 0 or CPUDef.PS.SF
*/
CPUSim.prototype.getSF = function()
{
return (this.resultParitySign & 0x80)? CPUDef.PS.SF : 0;
};
/**
* getIF()
*
* @this {CPUSim}
* @return {number} 0 or CPUDef.PS.IF
*/
CPUSim.prototype.getIF = function()
{
return (this.regPS & CPUDef.PS.IF);
};
/**
* clearCF()
*
* @this {CPUSim}
*/
CPUSim.prototype.clearCF = function()
{
this.resultZeroCarry &= 0xff;
};
/**
* clearPF()
*
* @this {CPUSim}
*/
CPUSim.prototype.clearPF = function()
{
if (this.getPF()) this.resultParitySign ^= 0x1;
};
/**
* clearAF()
*
* @this {CPUSim}
*/
CPUSim.prototype.clearAF = function()
{
this.resultAuxOverflow = (this.resultParitySign & 0x10) | (this.resultAuxOverflow & ~0x10);
};
/**
* clearZF()
*
* @this {CPUSim}
*/
CPUSim.prototype.clearZF = function()
{
this.resultZeroCarry |= 0xff;
};
/**
* clearSF()
*
* @this {CPUSim}
*/
CPUSim.prototype.clearSF = function()
{
if (this.getSF()) this.resultParitySign ^= 0xc0;
};
/**
* clearIF()
*
* @this {CPUSim}
*/
CPUSim.prototype.clearIF = function()
{
this.regPS &= ~CPUDef.PS.IF;
};
/**
* setCF()
*
@ -551,71 +445,6 @@ CPUSim.prototype.setCF = function()
this.resultZeroCarry |= 0x100;
};
/**
* setPF()
*
* @this {CPUSim}
*/
CPUSim.prototype.setPF = function()
{
if (!this.getPF()) this.resultParitySign ^= 0x1;
};
/**
* setAF()
*
* @this {CPUSim}
*/
CPUSim.prototype.setAF = function()
{
this.resultAuxOverflow = (~this.resultParitySign & 0x10) | (this.resultAuxOverflow & ~0x10);
};
/**
* setZF()
*
* @this {CPUSim}
*/
CPUSim.prototype.setZF = function()
{
this.resultZeroCarry &= ~0xff;
};
/**
* setSF()
*
* @this {CPUSim}
*/
CPUSim.prototype.setSF = function()
{
if (!this.getSF()) this.resultParitySign ^= 0xc0;
};
/**
* setIF()
*
* @this {CPUSim}
*/
CPUSim.prototype.setIF = function()
{
this.regPS |= CPUDef.PS.IF;
};
/**
* updateAF(fAuxCarry)
*
* @this {CPUSim}
* @param {boolean} fAuxCarry
*/
CPUSim.prototype.updateAF = function(fAuxCarry)
{
if (fAuxCarry) {
this.setAF();
} else {
this.clearAF();
}
};
/**
* updateCF(fCarry)
*
@ -631,6 +460,176 @@ CPUSim.prototype.updateCF = function(fCarry)
}
};
/**
* clearPF()
*
* @this {CPUSim}
*/
CPUSim.prototype.clearPF = function()
{
if (this.getPF()) this.resultParitySign ^= 0x1;
};
/**
* getPF()
*
* @this {CPUSim}
* @return {number} 0 or CPUDef.PS.PF
*/
CPUSim.prototype.getPF = function()
{
return (CPUDef.PARITY[this.resultParitySign & 0xff])? CPUDef.PS.PF : 0;
};
/**
* setPF()
*
* @this {CPUSim}
*/
CPUSim.prototype.setPF = function()
{
if (!this.getPF()) this.resultParitySign ^= 0x1;
};
/**
* clearAF()
*
* @this {CPUSim}
*/
CPUSim.prototype.clearAF = function()
{
this.resultAuxOverflow = (this.resultParitySign & 0x10) | (this.resultAuxOverflow & ~0x10);
};
/**
* getAF()
*
* @this {CPUSim}
* @return {number} 0 or CPUDef.PS.AF
*/
CPUSim.prototype.getAF = function()
{
return ((this.resultParitySign ^ this.resultAuxOverflow) & 0x10)? CPUDef.PS.AF : 0;
};
/**
* setAF()
*
* @this {CPUSim}
*/
CPUSim.prototype.setAF = function()
{
this.resultAuxOverflow = (~this.resultParitySign & 0x10) | (this.resultAuxOverflow & ~0x10);
};
/**
* updateAF(fAuxCarry)
*
* @this {CPUSim}
* @param {boolean} fAuxCarry
*/
CPUSim.prototype.updateAF = function(fAuxCarry)
{
if (fAuxCarry) {
this.setAF();
} else {
this.clearAF();
}
};
/**
* clearZF()
*
* @this {CPUSim}
*/
CPUSim.prototype.clearZF = function()
{
this.resultZeroCarry |= 0xff;
};
/**
* getZF()
*
* @this {CPUSim}
* @return {number} 0 or CPUDef.PS.ZF
*/
CPUSim.prototype.getZF = function()
{
return (this.resultZeroCarry & 0xff)? 0 : CPUDef.PS.ZF;
};
/**
* setZF()
*
* @this {CPUSim}
*/
CPUSim.prototype.setZF = function()
{
this.resultZeroCarry &= ~0xff;
};
/**
* clearSF()
*
* @this {CPUSim}
*/
CPUSim.prototype.clearSF = function()
{
if (this.getSF()) this.resultParitySign ^= 0xc0;
};
/**
* getSF()
*
* @this {CPUSim}
* @return {number} 0 or CPUDef.PS.SF
*/
CPUSim.prototype.getSF = function()
{
return (this.resultParitySign & 0x80)? CPUDef.PS.SF : 0;
};
/**
* setSF()
*
* @this {CPUSim}
*/
CPUSim.prototype.setSF = function()
{
if (!this.getSF()) this.resultParitySign ^= 0xc0;
};
/**
* clearIF()
*
* @this {CPUSim}
*/
CPUSim.prototype.clearIF = function()
{
this.regPS &= ~CPUDef.PS.IF;
};
/**
* getIF()
*
* @this {CPUSim}
* @return {number} 0 or CPUDef.PS.IF
*/
CPUSim.prototype.getIF = function()
{
return (this.regPS & CPUDef.PS.IF);
};
/**
* setIF()
*
* @this {CPUSim}
*/
CPUSim.prototype.setIF = function()
{
this.regPS |= CPUDef.PS.IF;
};
/**
* getPS()
*
@ -639,7 +638,7 @@ CPUSim.prototype.updateCF = function(fCarry)
*/
CPUSim.prototype.getPS = function()
{
return (this.regPS & ~CPUDef.PS.INDIRECT) | (this.getSF() | this.getZF() | this.getAF() | this.getPF() | this.getCF());
return (this.regPS & ~CPUDef.PS.RESULT) | (this.getSF() | this.getZF() | this.getAF() | this.getPF() | this.getCF());
};
/**
@ -656,8 +655,31 @@ CPUSim.prototype.setPS = function(regPS)
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;
Component.assert((regPS & CPUDef.PS.INDIRECT) == (this.getPS() & CPUDef.PS.INDIRECT));
this.regPS = (this.regPS & ~(CPUDef.PS.RESULT | CPUDef.PS.INTERNAL)) | (regPS & CPUDef.PS.INTERNAL) | CPUDef.PS.SET;
Component.assert((regPS & CPUDef.PS.RESULT) == (this.getPS() & CPUDef.PS.RESULT));
};
/**
* getPSW()
*
* @this {CPUSim}
* @return {number}
*/
CPUSim.prototype.getPSW = function()
{
return (this.getPS() & CPUDef.PS.MASK) | (this.regA << 8);
};
/**
* setPSW(w)
*
* @this {CPUSim}
* @param {number} w
*/
CPUSim.prototype.setPSW = function(w)
{
this.setPS((w & CPUDef.PS.MASK) | (this.regPS & ~CPUDef.PS.MASK));
this.regA = w >> 8;
};
/**

View file

@ -321,10 +321,15 @@ if (DEBUGGER) {
Debugger.REG_HL = 0x0A;
Debugger.REG_SP = 0x0B;
Debugger.REG_PC = 0x0C;
Debugger.REG_PS = 0x0D; // aka PSW (aka AF if Z80-style mnemonics)
Debugger.REG_PS = 0x0D;
Debugger.REG_PSW = 0x0E; // aka AF if Z80-style mnemonics
/*
* NOTE: "PS" is the complete processor status, which includes bits like the Interrupt flag (IF),
* which is NOT the same as "PSW", which is the low 8 bits of "PS" combined with "A" in the high byte.
*/
Debugger.REGS = [
"B", "C", "D", "E", "H", "L", "M", "A", "BC", "DE", "HL", "SP", "PC", "PSW"
"B", "C", "D", "E", "H", "L", "M", "A", "BC", "DE", "HL", "SP", "PC", "PS", "PSW"
];
/*
@ -370,7 +375,7 @@ if (DEBUGGER) {
Debugger.TYPE_HL = (Debugger.REG_HL << 8 | Debugger.TYPE_REG | Debugger.TYPE_WORD);
Debugger.TYPE_SP = (Debugger.REG_SP << 8 | Debugger.TYPE_REG | Debugger.TYPE_WORD);
Debugger.TYPE_PC = (Debugger.REG_PC << 8 | Debugger.TYPE_REG | Debugger.TYPE_WORD);
Debugger.TYPE_PS = (Debugger.REG_PS << 8 | Debugger.TYPE_REG | Debugger.TYPE_WORD);
Debugger.TYPE_PSW = (Debugger.REG_PSW<< 8 | Debugger.TYPE_REG | Debugger.TYPE_WORD);
/*
* TYPE_OTHER bit definitions
@ -642,11 +647,11 @@ if (DEBUGGER) {
/* 0xEE */ [Debugger.INS.XRI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xEF */ [Debugger.INS.RST, Debugger.TYPE_INT],
/* 0xF0 */ [Debugger.INS.RP],
/* 0xF1 */ [Debugger.INS.POP, Debugger.TYPE_PS],
/* 0xF1 */ [Debugger.INS.POP, Debugger.TYPE_PSW],
/* 0xF2 */ [Debugger.INS.JP, Debugger.TYPE_ADDR],
/* 0xF3 */ [Debugger.INS.DI],
/* 0xF4 */ [Debugger.INS.CP, Debugger.TYPE_ADDR],
/* 0xF5 */ [Debugger.INS.PUSH, Debugger.TYPE_PS],
/* 0xF5 */ [Debugger.INS.PUSH, Debugger.TYPE_PSW],
/* 0xF6 */ [Debugger.INS.ORI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xF7 */ [Debugger.INS.RST, Debugger.TYPE_INT],
/* 0xF8 */ [Debugger.INS.RM],
@ -1347,8 +1352,8 @@ if (DEBUGGER) {
if (off == null) {
i = usr.indexOf(Debugger.REGS, sReg);
} else {
i = usr.indexOf(Debugger.REGS, sReg.substr(off, 3));
if (i < 0) i = usr.indexOf(Debugger.REGS, sReg.substr(off, 2));
i = usr.indexOf(Debugger.REGS, sReg.substr(off, 2));
if (i < 0) i = usr.indexOf(Debugger.REGS, sReg.substr(off, 1));
}
return i;
};
@ -1382,6 +1387,7 @@ if (DEBUGGER) {
case Debugger.REG_SP:
case Debugger.REG_PC:
case Debugger.REG_PS:
case Debugger.REG_PSW:
cch = 4;
break;
}
@ -1442,7 +1448,10 @@ if (DEBUGGER) {
n = cpu.getPC();
break;
case Debugger.REG_PS:
n = (cpu.regA << 8) | (cpu.getPS() & 0xff);
n = cpu.getPS();
break;
case Debugger.REG_PSW:
n = cpu.getPSW();
break;
default:
break;
@ -2581,29 +2590,29 @@ if (DEBUGGER) {
{
var b;
switch (sFlag) {
case 'I':
case "IF":
b = this.cpu.getIF();
break;
case 'S':
case "SF":
b = this.cpu.getSF();
break;
case 'Z':
case "ZF":
b = this.cpu.getZF();
break;
case 'A':
case "AF":
b = this.cpu.getAF();
break;
case 'P':
case "PF":
b = this.cpu.getPF();
break;
case 'C':
case "CF":
b = this.cpu.getCF();
break;
default:
b = 0;
break;
}
return sFlag + (b? '1' : '0') + ' ';
return sFlag.charAt(0) + (b? '1' : '0') + ' ';
};
/**
@ -2624,7 +2633,7 @@ if (DEBUGGER) {
*
* Sample 8080 register dump:
*
* A=00 BC=0000 DE=0000 HL=0000 SP=0000 PSW=0002 I0 S0 Z0 A0 P0 C0
* A=00 BC=0000 DE=0000 HL=0000 SP=0000 I0 S0 Z0 A0 P0 C0
* 0000 00 NOP
*
* @this {Debugger}
@ -2638,8 +2647,8 @@ if (DEBUGGER) {
this.getRegOutput(Debugger.REG_DE) +
this.getRegOutput(Debugger.REG_HL) +
this.getRegOutput(Debugger.REG_SP) +
this.getFlagOutput('I') + this.getFlagOutput('S') + this.getFlagOutput('Z') +
this.getFlagOutput('A') + this.getFlagOutput('P') + this.getFlagOutput('C');
this.getFlagOutput("IF") + this.getFlagOutput("SF") + this.getFlagOutput("ZF") +
this.getFlagOutput("AF") + this.getFlagOutput("PF") + this.getFlagOutput("CF");
return s;
};
@ -4131,22 +4140,25 @@ if (DEBUGGER) {
case "PS":
cpu.setPS(w);
break;
case 'C':
case "PSW":
cpu.setPSW(w);
break;
case "CF":
if (w) cpu.setCF(); else cpu.clearCF();
break;
case 'P':
case "PF":
if (w) cpu.setPF(); else cpu.clearPF();
break;
case 'A':
case "AF":
if (w) cpu.setAF(); else cpu.clearAF();
break;
case 'Z':
case "ZF":
if (w) cpu.setZF(); else cpu.clearZF();
break;
case 'S':
case "SF":
if (w) cpu.setSF(); else cpu.clearSF();
break;
case 'I':
case "IF":
if (w) cpu.setIF(); else cpu.clearIF();
break;
default: