- [FIX] Opcode 0x28 (PLP) usava la microinstrucció miPushP en compte de la correcta miPullP.
- [FIX Opcode 0x38 estaba etiquetat com a ESC, en compte del correcte SEC. - [FIX] Relative branching es feia incorrectament. - [FIX] Afegida emulació del hardware bug en opcode 0x6c (indirect jump). - [FIX] registres de 16 bits implementats amb funcions explicites per a evitar errors de aliasing (puto C++). - [FIX] Implementats els modes BCD en ADC i SBC - [FIX] Arreglat el càlcul del signe al creuar una pàgina de memòria.
This commit is contained in:
@@ -15,45 +15,37 @@ namespace m6502
|
||||
{
|
||||
uint8_t interrupt_vector = 0xfe;
|
||||
|
||||
uint8_t regs[13];
|
||||
uint8_t rA;
|
||||
uint8_t rX;
|
||||
uint8_t rY;
|
||||
uint8_t rS;
|
||||
uint8_t rP;
|
||||
uint8_t rPC_lo;
|
||||
uint8_t rPC_hi;
|
||||
//#define rPC (*_rPC)
|
||||
|
||||
uint8_t *_rA = ®s[0];
|
||||
uint8_t *_rX = ®s[1];
|
||||
uint8_t *_rY = ®s[2];
|
||||
uint8_t *_rS = ®s[3];
|
||||
uint8_t *_rP = ®s[4];
|
||||
uint8_t *_rPC_lo = ®s[5];
|
||||
uint8_t *_rPC_hi = ®s[6];
|
||||
uint16_t *_rPC = (uint16_t*)®s[5];
|
||||
uint8_t rB;
|
||||
uint8_t rT;
|
||||
uint8_t rI;
|
||||
uint8_t rAD_lo;
|
||||
uint8_t rAD_hi;
|
||||
//#define rAD (*_rAD)
|
||||
uint8_t rTEMP_lo;
|
||||
uint8_t rTEMP_hi;
|
||||
//#define rTEMP (*_rTEMP)
|
||||
|
||||
uint8_t *_rB = ®s[7];
|
||||
uint8_t *_rT = ®s[8];
|
||||
uint8_t *_rI = ®s[9];
|
||||
uint8_t *_rAD_lo = ®s[10];
|
||||
uint8_t *_rAD_hi = ®s[11];
|
||||
uint16_t *_rAD = (uint16_t*)®s[10];
|
||||
uint8_t *_rTEMP_lo = ®s[12];
|
||||
uint8_t *_rTEMP_hi = ®s[13];
|
||||
uint16_t *_rTEMP = (uint16_t*)®s[12];
|
||||
// Explicit 16-bit accessors prevent UB and stay host-endian safe
|
||||
inline uint16_t get_PC() { return (uint16_t)rPC_lo | ((uint16_t)rPC_hi << 8); }
|
||||
inline void set_PC(uint16_t val) { rPC_lo = val & 0xFF; rPC_hi = val >> 8; }
|
||||
inline uint16_t inc_PC() { if (++rPC_lo == 0) rPC_hi++; return get_PC(); } // Natural 16-bit bump
|
||||
|
||||
#define rA (*_rA)
|
||||
#define rX (*_rX)
|
||||
#define rY (*_rY)
|
||||
#define rS (*_rS)
|
||||
#define rP (*_rP)
|
||||
#define rPC_lo (*_rPC_lo)
|
||||
#define rPC_hi (*_rPC_hi)
|
||||
#define rPC (*_rPC)
|
||||
inline uint16_t get_AD() { return (uint16_t)rAD_lo | ((uint16_t)rAD_hi << 8); }
|
||||
inline void set_AD(uint16_t val) { rAD_lo = val & 0xFF; rAD_hi = val >> 8; }
|
||||
inline void inc_AD() { if (++rAD_lo == 0) rAD_hi++; } // Natural 16-bit bump
|
||||
|
||||
#define rB (*_rB)
|
||||
#define rT (*_rT)
|
||||
#define rI (*_rI)
|
||||
#define rAD_lo (*_rAD_lo)
|
||||
#define rAD_hi (*_rAD_hi)
|
||||
#define rAD (*_rAD)
|
||||
#define rTEMP_lo (*_rTEMP_lo)
|
||||
#define rTEMP_hi (*_rTEMP_hi)
|
||||
#define rTEMP (*_rTEMP)
|
||||
inline uint16_t get_TEMP() { return (uint16_t)rTEMP_lo | ((uint16_t)rTEMP_hi << 8); }
|
||||
inline void set_TEMP(uint16_t val) { rTEMP_lo = val & 0xFF; rTEMP_hi = val >> 8; }
|
||||
inline void inc_TEMP() { if (++rTEMP_lo == 0) rTEMP_hi++; } // Natural 16-bit bump
|
||||
|
||||
uint8_t microcode[256];
|
||||
uint8_t microcode_pos = 0;
|
||||
@@ -136,7 +128,7 @@ namespace m6502
|
||||
/* 0x25 AND zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode },
|
||||
/* 0x26 ROL zpg */ { miFetchOperandLo, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode },
|
||||
/* 0x27 --- */ { miFetchOpcode },
|
||||
/* 0x28 PLP */ { miFetchOperandLo, miPushP, miFetchOpcode },
|
||||
/* 0x28 PLP */ { miFetchOperandLo, miPullP, miFetchOpcode },
|
||||
/* 0x29 AND imm */ { miFetchOperandLo, miFetchOpcode },
|
||||
/* 0x2A ROL A */ { miFakeFetchOperand, miFetchOpcode },
|
||||
/* 0x2B --- */ { miFetchOpcode },
|
||||
@@ -153,7 +145,7 @@ namespace m6502
|
||||
/* 0x35 AND zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miFetchOpcode },
|
||||
/* 0x36 ROL zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode },
|
||||
/* 0x37 --- */ { miFetchOpcode },
|
||||
/* 0x38 ESC */ { miFetchOperandLo, miFetchOpcode },
|
||||
/* 0x38 SEC */ { miFetchOperandLo, miFetchOpcode },
|
||||
/* 0x39 AND abs,Y */ { miFetchOperandLo, miFetchOperandHiAndIndexY, miReadAddressAndSkip, miReadAddress, miFetchOpcode },
|
||||
/* 0x3A --- */ { miFetchOpcode },
|
||||
/* 0x3B --- */ { miFetchOpcode },
|
||||
@@ -375,6 +367,61 @@ namespace m6502
|
||||
if (flags&fV) rP = ( (rTEMP_lo ^ rA) & (rTEMP_lo ^ rB) & 0x80 ) ? rP | fV : rP & ~fV;
|
||||
}
|
||||
|
||||
void DoDecimalADC()
|
||||
{
|
||||
uint8_t c_in = (rP & fC) ? 1 : 0;
|
||||
uint8_t low = (rA & 0x0F) + (rB & 0x0F) + c_in;
|
||||
if (low > 9) low += 6;
|
||||
uint8_t high = (rA >> 4) + (rB >> 4) + (low > 0x0F ? 1 : 0);
|
||||
|
||||
// Set Zero and Negative flags based on BINARY addition result (NMOS 6502 accurate)
|
||||
uint16_t bin_sum = (uint16_t)rA + rB + c_in;
|
||||
rTEMP_lo = bin_sum & 0xFF;
|
||||
if (~(rA ^ rB) & (rA ^ rTEMP_lo) & 0x80) rP |= fV; else rP &= ~fV;
|
||||
SetFlags(fN | fZ);
|
||||
|
||||
if (high > 9) high += 6;
|
||||
rP = (high > 15) ? (rP | fC) : (rP & ~fC);
|
||||
rA = ((high << 4) | (low & 0x0F)) & 0xFF;
|
||||
}
|
||||
|
||||
void DoDecimalSBC()
|
||||
{
|
||||
uint8_t c_in = (rP & fC) ? 1 : 0;
|
||||
uint16_t bin_diff = (uint16_t)rA - rB - (1 - c_in);
|
||||
|
||||
int low = (rA & 0x0F) - (rB & 0x0F) - (1 - c_in);
|
||||
int high = (rA >> 4) - (rB >> 4);
|
||||
if (low < 0) { low -= 6; high--; }
|
||||
if (high < 0) high -= 6;
|
||||
|
||||
rTEMP_lo = bin_diff & 0xFF;
|
||||
if ((rA ^ rB) & (rA ^ rTEMP_lo) & 0x80) rP |= fV; else rP &= ~fV;
|
||||
if (!(bin_diff & 0x100)) rP |= fC; else rP &= ~fC;
|
||||
SetFlags(fN | fZ);
|
||||
|
||||
rA = ((high << 4) | (low & 0x0F)) & 0xFF;
|
||||
}
|
||||
|
||||
void DoBinaryADC()
|
||||
{
|
||||
uint8_t c_in = (rP & fC) ? 1 : 0;
|
||||
uint16_t sum = (uint16_t)rA + rB + c_in;
|
||||
rTEMP_lo = sum & 0xFF;
|
||||
if (sum > 0xFF) rP |= fC; else rP &= ~fC;
|
||||
if (~(rA ^ rB) & (rA ^ rTEMP_lo) & 0x80) rP |= fV; else rP &= ~fV;
|
||||
SetFlags(fN | fZ);
|
||||
rA = rTEMP_lo;
|
||||
}
|
||||
|
||||
void DoBinarySBC()
|
||||
{
|
||||
uint8_t tmp = rB;
|
||||
rB ^= 0xFF;
|
||||
DoBinaryADC();
|
||||
rB = tmp;
|
||||
}
|
||||
|
||||
void DoOpcodeWork()
|
||||
{
|
||||
if (rI==0xCA) { rX--; rB = rX; SetFlags(fN|fZ); return; } /* DEX */
|
||||
@@ -405,21 +452,27 @@ namespace m6502
|
||||
/* LDY */ rTEMP_lo = rB; SetFlags(fN|fZ); rY = rTEMP_lo; break;
|
||||
} else if ( ((rI&0xD3)==0xC0) && (((rI>>2)&3)!=2) ) {
|
||||
if ( (rI&0xf0)==0xC0 ) {
|
||||
/* CPY */ rTEMP = rY + ~rB; SetFlags(fN|fZ|fC); break;
|
||||
/* CPY */ set_TEMP(rY + ~rB); SetFlags(fN|fZ|fC); break;
|
||||
} else {
|
||||
/* CPX */ rTEMP = rX + ~rB; SetFlags(fN|fZ|fC); break;
|
||||
/* CPX */ set_TEMP(rX + ~rB); SetFlags(fN|fZ|fC); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: /* ALU */
|
||||
|
||||
switch ((rI>>5)&0x07) {
|
||||
case 0: /* ORA */ rTEMP_lo = rA | rB; SetFlags(fN|fZ); rA = rTEMP_lo; break;
|
||||
case 1: /* AND */ rTEMP_lo = rA & rB; SetFlags(fN|fZ); rA = rTEMP_lo; break;
|
||||
case 2: /* EOR */ rTEMP_lo = rA ^ rB; SetFlags(fN|fZ); rA = rTEMP_lo; break;
|
||||
case 3: /* ADC */ rTEMP = rA + rB + fC; SetFlags(fN|fV|fZ|fC); rA = rTEMP_lo; break;
|
||||
case 7: /* SBC */ if (rP & fD) DoDecimalSBC(); else DoBinarySBC(); break;
|
||||
case 3: /* ADC */ if (rP & fD) DoDecimalADC(); else DoBinaryADC(); break;
|
||||
case 5: /* LDA */ rTEMP_lo = rB; SetFlags(fN|fZ); rA = rTEMP_lo; break;
|
||||
case 6: /* CMP */ rTEMP = rA + ~rB; SetFlags(fN|fZ|fC); break;
|
||||
case 7: /* SBC */ rTEMP = rA + ~rB + fC; SetFlags(fN|fV|fZ|fC); rA = rTEMP_lo; break;
|
||||
case 6: /* CMP */
|
||||
uint16_t diff = (uint16_t)rA - rB;
|
||||
rP = (diff < 0x100) ? (rP | fC) : (rP & ~fC);
|
||||
rTEMP_lo = diff & 0xFF;
|
||||
SetFlags(fN|fZ);
|
||||
break;
|
||||
};
|
||||
if ( (rI==0x24) || (rI==0x2C) ) /* BIT */ { rTEMP_lo = rA & rB; rP = (rP&~(fN|fV)) | (rB&(fN|fV)); SetFlags(fZ); }
|
||||
break;
|
||||
@@ -467,15 +520,15 @@ namespace m6502
|
||||
void FetchOpcode()
|
||||
{
|
||||
DoOpcodeWork();
|
||||
rI = mem::read(rPC++);
|
||||
rI = mem::read(get_PC()); inc_PC();
|
||||
int i=0; do { microcode[microcode_last++] = instructions[rI][i++]; } while (instructions[rI][i-1] != miFetchOpcode);
|
||||
}
|
||||
|
||||
void FakeFetchOperand() { rAD_lo = mem::read(rPC); }
|
||||
void FetchOperandLo() { rTEMP = rAD_lo = rB = mem::read(rPC++); }
|
||||
void FetchOperandHi() { rAD_hi = mem::read(rPC++); }
|
||||
void FetchOperandHiAndIndexX() { rAD_hi = mem::read(rPC++); rTEMP = rAD_lo + rX; rAD_lo = rTEMP_lo; }
|
||||
void FetchOperandHiAndIndexY() { rAD_hi = mem::read(rPC++); rTEMP = rAD_lo + rY; rAD_lo = rTEMP_lo; }
|
||||
void FakeFetchOperand() { rAD_lo = mem::read(get_PC()); }
|
||||
void FetchOperandLo() { rAD_lo = rB = mem::read(get_PC()); inc_PC(); set_TEMP(rB); }
|
||||
void FetchOperandHi() { rAD_hi = mem::read(get_PC()); inc_PC(); }
|
||||
void FetchOperandHiAndIndexX() { rAD_hi = mem::read(get_PC()); inc_PC(); set_TEMP(rAD_lo + rX); rAD_lo = rTEMP_lo; }
|
||||
void FetchOperandHiAndIndexY() { rAD_hi = mem::read(get_PC()); inc_PC(); set_TEMP(rAD_lo + rY); rAD_lo = rTEMP_lo; }
|
||||
|
||||
void PushPCHi() { mem::write(0x0100+(rS--), rPC_hi); }
|
||||
void PushPCLo() { mem::write(0x0100+(rS--), rPC_lo); }
|
||||
@@ -483,27 +536,51 @@ namespace m6502
|
||||
void PCLoInt() { rPC_lo = mem::read(0xff00+interrupt_vector); }
|
||||
void PCHiInt() { rPC_hi = mem::read(0xff00+interrupt_vector+1); }
|
||||
|
||||
void IndexX() { rB = mem::read(rAD); rAD_lo += rX; }
|
||||
void FetchAddressLo() { rT = mem::read(rAD++); }
|
||||
void FetchAddressHi() { rAD_hi = mem::read(rAD); rAD_lo = rT; }
|
||||
void FetchAddressHiAndIndex() { rAD_hi = mem::read(rAD); rTEMP = rAD_lo + rY; rAD_lo = rTEMP_lo; }
|
||||
void ReadAddress() { rB = mem::read(rAD); rAD_hi += rTEMP_hi; }
|
||||
void IndexX() { rB = mem::read(get_AD()); rAD_lo += rX; }
|
||||
void FetchAddressLo() { rT = mem::read(get_AD()); inc_AD(); }
|
||||
void FetchAddressHi() { rAD_hi = mem::read(get_AD()); rAD_lo = rT; }
|
||||
void FetchAddressHiAndIndex() { rAD_hi = mem::read(get_AD()); set_TEMP(rAD_lo + rY); rAD_lo = rTEMP_lo; }
|
||||
void ReadAddress() { rB = mem::read(get_AD()); rAD_hi += rTEMP_hi; }
|
||||
|
||||
void ReadAddressAndSkip() { rB = mem::read(rAD); rAD_hi += rTEMP_hi; if (rTEMP_hi) InsertFetchOpcode(); }
|
||||
void WriteRegister() { mem::write(rAD, (rI&3)==1 ? rA : (rI&3)==2 ? rX : rY ); }
|
||||
void WriteAddress() { mem::write(rAD, rB); DoRMW(); }
|
||||
void ReadAddressAndSkip() { rB = mem::read(get_AD()); rAD_hi += rTEMP_hi; if (rTEMP_hi) InsertFetchOpcode(); }
|
||||
void WriteRegister() { mem::write(get_AD(), (rI&3)==1 ? rA : (rI&3)==2 ? rX : rY ); }
|
||||
void WriteAddress() { mem::write(get_AD(), rB); DoRMW(); }
|
||||
void PushA() { mem::write(0x0100+(rS--), rA); }
|
||||
void FetchOperandAndCheckBranch() { FetchOperandLo(); if (!BranchCondition()) InsertFetchOpcode(); else { rT = rPC_hi; rPC = rPC + (int8_t)rB; } }
|
||||
void FetchOperandAndCheckBranch() {
|
||||
int8_t offset = (int8_t)mem::read(get_PC()); inc_PC();
|
||||
rB = (uint8_t)offset;
|
||||
|
||||
if (!BranchCondition()) {
|
||||
InsertFetchOpcode();
|
||||
return;
|
||||
}
|
||||
set_TEMP(rPC_lo + offset);
|
||||
rT = rPC_hi;
|
||||
rPC_lo = rTEMP_lo;
|
||||
}
|
||||
|
||||
void CheckIfPageCrossed() {
|
||||
FakeFetchOperand();
|
||||
|
||||
int8_t offset = (int8_t)rB;
|
||||
|
||||
if (offset >= 0 && rTEMP_hi != 0) {
|
||||
rPC_hi++;
|
||||
} else if (offset < 0 && rTEMP_hi == 0) {
|
||||
rPC_hi--;
|
||||
} else {
|
||||
InsertFetchOpcode();
|
||||
}
|
||||
}
|
||||
|
||||
void CheckIfPageCrossed() { FakeFetchOperand(); if (rPC_hi == rT) InsertFetchOpcode(); }
|
||||
void PullPCHi() { rPC_hi = mem::read(0x0100+(++rS)); }
|
||||
void PullPCLo() { rPC_lo = mem::read(0x0100+(++rS)); }
|
||||
void PullP() { rP = mem::read(0x0100+(++rS)); }
|
||||
void PullA() { rA = mem::read(0x0100+(++rS)); }
|
||||
|
||||
void IncrementPC() { rPC++; }
|
||||
void FetchAddressHiToPC() { rPC_hi = mem::read(rAD); rPC_lo = rT; }
|
||||
void IndexY() { rB = mem::read(rAD); rAD_lo += rY; }
|
||||
void IncrementPC() { inc_PC(); }
|
||||
void FetchAddressHiToPC() { uint16_t high_addr = (get_AD() & 0xFF00) | ((get_AD() + 1) & 0x00FF); rPC_hi = mem::read(high_addr); rPC_lo = rT; }
|
||||
void IndexY() { rB = mem::read(get_AD()); rAD_lo += rY; }
|
||||
|
||||
void (*microinstructions[miNumMicroinstructions])(void) {
|
||||
FetchOpcode, FakeFetchOperand, FetchOperandLo, FetchOperandHi, FetchOperandHiAndIndexX, FetchOperandHiAndIndexY,
|
||||
|
||||
Reference in New Issue
Block a user