Make the 6502 a little more compatible with other processor implementations.

Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian.Conlon 2017-07-17 13:46:06 +01:00
parent 867b0d5260
commit 4f491f110e
5 changed files with 123 additions and 159 deletions

View File

@ -12,18 +12,36 @@
namespace EightBit {
class MOS6502 : public Processor {
public:
struct opcode_decoded_t {
int aaa;
int bbb;
int cc;
opcode_decoded_t() {
aaa = bbb = cc = 0;
}
opcode_decoded_t(uint8_t opcode) {
aaa = (opcode & 0b11100000) >> 5; // 0 - 7
bbb = (opcode & 0b00011100) >> 2; // 0 - 7
cc = (opcode & 0b00000011); // 0 - 3
}
};
enum StatusBits {
NF = 0x80, // Negative
VF = 0x40, // Overflow
RF = 0x20, // reserved
BF = 0x10, // Brk
DF = 0x08, // D (use BCD for arithmetic)
IF = 0x04, // I (IRQ disable)
ZF = 0x02, // Zero
CF = 0x01, // Carry
NF = Bit7, // Negative
VF = Bit6, // Overflow
RF = Bit5, // reserved
BF = Bit4, // Brk
DF = Bit3, // D (use BCD for arithmetic)
IF = Bit2, // I (IRQ disable)
ZF = Bit1, // Zero
CF = Bit0, // Carry
};
MOS6502(Memory& memory);
virtual ~MOS6502();
Signal<MOS6502> ExecutingInstruction;
Signal<MOS6502> ExecutedInstruction;
@ -58,6 +76,8 @@ namespace EightBit {
virtual int Execute(uint8_t cell);
private:
register16_t& MEMPTR() { return m_memptr; }
void adjustZero(uint8_t datum) { clearFlag(P(), ZF, datum); }
void adjustNegative(uint8_t datum) { setFlag(P(), NF, datum & NF); }
@ -79,61 +99,55 @@ namespace EightBit {
#pragma region Addresses
void Address_Absolute() {
FetchWord(m_memptr);
FetchWord(MEMPTR());
}
void Address_ZeroPage() {
m_memptr.low = FetchByte();
m_memptr.high = 0;
MEMPTR().low = FetchByte();
MEMPTR().high = 0;
}
void Address_ZeroPageIndirect() {
Address_ZeroPage();
m_memory.ADDRESS() = m_memptr;
GetWord(m_memptr);
m_memory.ADDRESS() = MEMPTR();
GetWord(MEMPTR());
}
void Address_Indirect() {
Address_Absolute();
m_memory.ADDRESS() = m_memptr;
GetWord(m_memptr);
}
void Address_IndirectX() {
Address_Absolute();
m_memory.ADDRESS().word = m_memptr.word + X();
GetWord(m_memptr);
m_memory.ADDRESS() = MEMPTR();
GetWord(MEMPTR());
}
void Address_ZeroPageX() {
Address_ZeroPage();
m_memptr.low += X();
MEMPTR().low += X();
}
void Address_ZeroPageY() {
Address_ZeroPage();
m_memptr.low += Y();
MEMPTR().low += Y();
}
void Address_AbsoluteX() {
Address_Absolute();
m_memptr.word += X();
MEMPTR().word += X();
}
void Address_AbsoluteY() {
Address_Absolute();
m_memptr.word += Y();
MEMPTR().word += Y();
}
void Address_IndexedIndirectX() {
Address_ZeroPageX();
m_memory.ADDRESS() = m_memptr;
GetWord(m_memptr);
m_memory.ADDRESS() = MEMPTR();
GetWord(MEMPTR());
}
void Address_IndirectIndexedY() {
Address_ZeroPageIndirect();
m_memptr.word += Y();
MEMPTR().word += Y();
}
#pragma endregion Addresses
@ -154,22 +168,22 @@ namespace EightBit {
uint8_t& AM_Absolute() {
m_busRW = true;
Address_Absolute();
m_memory.ADDRESS() = m_memptr;
m_memory.ADDRESS() = MEMPTR();
return m_memory.reference();
}
uint8_t& AM_ZeroPage() {
m_busRW = true;
Address_ZeroPage();
m_memory.ADDRESS() = m_memptr;
m_memory.ADDRESS() = MEMPTR();
return m_memory.reference();
}
uint8_t& AM_AbsoluteX(bool read = true) {
m_busRW = true;
Address_AbsoluteX();
m_memory.ADDRESS() = m_memptr;
if (read && (m_memory.ADDRESS().low == 0xff))
m_memory.ADDRESS() = MEMPTR();
if (read && (m_memory.ADDRESS().low == Mask8))
++cycles;
return m_memory.reference();
}
@ -177,8 +191,8 @@ namespace EightBit {
uint8_t& AM_AbsoluteY(bool read = true) {
m_busRW = true;
Address_AbsoluteY();
m_memory.ADDRESS() = m_memptr;
if (read && (m_memory.ADDRESS().low == 0xff))
m_memory.ADDRESS() = MEMPTR();
if (read && (m_memory.ADDRESS().low == Mask8))
++cycles;
return m_memory.reference();
}
@ -186,29 +200,29 @@ namespace EightBit {
uint8_t& AM_ZeroPageX() {
m_busRW = true;
Address_ZeroPageX();
m_memory.ADDRESS() = m_memptr;
m_memory.ADDRESS() = MEMPTR();
return m_memory.reference();
}
uint8_t& AM_ZeroPageY() {
m_busRW = true;
Address_ZeroPageY();
m_memory.ADDRESS() = m_memptr;
m_memory.ADDRESS() = MEMPTR();
return m_memory.reference();
}
uint8_t& AM_IndexedIndirectX() {
m_busRW = true;
Address_IndexedIndirectX();
m_memory.ADDRESS() = m_memptr;
m_memory.ADDRESS() = MEMPTR();
return m_memory.reference();
}
uint8_t& AM_IndirectIndexedY(bool read = true) {
m_busRW = true;
Address_IndirectIndexedY();
m_memory.ADDRESS() = m_memptr;
if (read && (m_memory.ADDRESS().low == 0xff))
m_memory.ADDRESS() = MEMPTR();
if (read && (m_memory.ADDRESS().low == Mask8))
++cycles;
return m_memory.reference();
}
@ -309,36 +323,22 @@ namespace EightBit {
#pragma endregion 6502 addressing modes
void DEC(uint8_t& output);
void ROR(uint8_t& output);
void LSR(uint8_t& output);
void BIT(uint8_t data);
void INC(uint8_t& output);
void ROL(uint8_t& output);
void ASL(uint8_t& output);
void ORA(uint8_t data);
void AND(uint8_t data);
void SBC(uint8_t data);
void SBC_b(uint8_t data);
void SBC_d(uint8_t data);
void EOR(uint8_t data);
void CMP(uint8_t first, uint8_t second);
void LDA(uint8_t data);
void LDY(uint8_t data);
void LDX(uint8_t data);
void ADC(uint8_t data);
void ADC_b(uint8_t data);
void ADC_d(uint8_t data);
@ -355,7 +355,6 @@ namespace EightBit {
void RTS();
void JMP_abs();
void JMP_ind();
void JMP_absxind();
void BRK();
const uint16_t PageOne = 0x100;
@ -372,6 +371,7 @@ namespace EightBit {
register16_t m_memptr;
std::array<int, 0x100> m_timings;
std::array<opcode_decoded_t, 0x100> m_decodedOpcodes;
bool m_busRW;
};

View File

@ -24,21 +24,28 @@ EightBit::MOS6502::MOS6502(Memory& memory)
};
}
EightBit::MOS6502::~MOS6502() {
}
void EightBit::MOS6502::initialise() {
Processor::initialise();
for (int i = 0; i < 0x100; ++i) {
m_decodedOpcodes[i] = i;
}
PC().word = 0;
X() = 0x80;
X() = Bit7;
Y() = 0;
A() = 0;
P() = 0;
setFlag(P(), RF);
S() = 0xff;
S() = Mask8;
m_memptr.word = 0;
MEMPTR().word = 0;
}
int EightBit::MOS6502::step() {
@ -89,15 +96,13 @@ int EightBit::MOS6502::Execute(uint8_t cell) {
// The aaa and cc bits determine the opcode, and the bbb
// bits determine the addressing mode.
auto aaa = (cell & 0b11100000) >> 5;
auto bbb = (cell & 0b00011100) >> 2;
auto cc = (cell & 0b00000011);
const auto& decoded = m_decodedOpcodes[cell];
switch (cc) {
switch (decoded.cc) {
case 0b00:
switch (aaa) {
switch (decoded.aaa) {
case 0b000:
switch (bbb) {
switch (decoded.bbb) {
case 0b000: // BRK
BRK();
break;
@ -115,7 +120,7 @@ int EightBit::MOS6502::Execute(uint8_t cell) {
}
break;
case 0b001:
switch (bbb) {
switch (decoded.bbb) {
case 0b000: // JSR
JSR_abs();
break;
@ -129,14 +134,14 @@ int EightBit::MOS6502::Execute(uint8_t cell) {
setFlag(P(), CF);
break;
default: // BIT
BIT(AM_00(bbb, false));
BIT(AM_00(decoded.bbb));
assert(m_busRW);
m_memory.read();
break;
}
break;
case 0b010:
switch (bbb) {
switch (decoded.bbb) {
case 0b000: // RTI
RTI();
break;
@ -157,7 +162,7 @@ int EightBit::MOS6502::Execute(uint8_t cell) {
}
break;
case 0b011:
switch (bbb) {
switch (decoded.bbb) {
case 0b000: // RTS
RTS();
break;
@ -178,9 +183,9 @@ int EightBit::MOS6502::Execute(uint8_t cell) {
}
break;
case 0b100:
switch (bbb) {
switch (decoded.bbb) {
case 0b010: // DEY
DEC(Y());
adjustNZ(--Y());
break;
case 0b100: // BCC
Branch(!(P() & CF));
@ -189,14 +194,14 @@ int EightBit::MOS6502::Execute(uint8_t cell) {
adjustNZ(A() = Y());
break;
default: // STY
AM_00(bbb, false);
AM_00(decoded.bbb, false);
assert(m_busRW);
m_memory.write(Y());
break;
}
break;
case 0b101:
switch (bbb) {
switch (decoded.bbb) {
case 0b010: // TAY
adjustNZ(Y() = A());
break;
@ -207,16 +212,16 @@ int EightBit::MOS6502::Execute(uint8_t cell) {
clearFlag(P(), VF);
break;
default: // LDY
LDY(AM_00(bbb));
adjustNZ(Y() = AM_00(decoded.bbb));
if (m_busRW)
m_memory.read();
break;
}
break;
case 0b110:
switch (bbb) {
switch (decoded.bbb) {
case 0b010: // INY
INC(Y());
adjustNZ(++Y());
break;
case 0b100: // BNE
Branch(!(P() & ZF));
@ -225,16 +230,16 @@ int EightBit::MOS6502::Execute(uint8_t cell) {
clearFlag(P(), DF);
break;
default: // CPY
CMP(Y(), AM_00(bbb));
CMP(Y(), AM_00(decoded.bbb));
if (m_busRW)
m_memory.read();
break;
}
break;
case 0b111:
switch (bbb) {
switch (decoded.bbb) {
case 0b010: // INX
INC(X());
adjustNZ(++X());
break;
case 0b100: // BEQ
Branch((P() & ZF) != 0);
@ -243,7 +248,7 @@ int EightBit::MOS6502::Execute(uint8_t cell) {
setFlag(P(), DF);
break;
default: // CPX
CMP(X(), AM_00(bbb));
CMP(X(), AM_00(decoded.bbb));
if (m_busRW)
m_memory.read();
break;
@ -252,44 +257,44 @@ int EightBit::MOS6502::Execute(uint8_t cell) {
}
break;
case 0b01:
switch (aaa) {
switch (decoded.aaa) {
case 0b000: // ORA
ORA(AM_01(bbb));
adjustNZ(A() |= AM_01(decoded.bbb));
if (m_busRW)
m_memory.read();
break;
case 0b001: // AND
AND(AM_01(bbb));
adjustNZ(A() &= AM_01(decoded.bbb));
if (m_busRW)
m_memory.read();
break;
case 0b010: // EOR
EOR(AM_01(bbb));
adjustNZ(A() ^= AM_01(decoded.bbb));
if (m_busRW)
m_memory.read();
break;
case 0b011: // ADC
ADC(AM_01(bbb));
ADC(AM_01(decoded.bbb));
if (m_busRW)
m_memory.read();
break;
case 0b100: // STA
AM_01(bbb, false);
AM_01(decoded.bbb, false);
assert(m_busRW);
m_memory.write(A());
break;
case 0b101: // LDA
LDA(AM_01(bbb));
adjustNZ(A() = AM_01(decoded.bbb));
if (m_busRW)
m_memory.read();
break;
case 0b110: // CMP
CMP(A(), AM_01(bbb));
CMP(A(), AM_01(decoded.bbb));
if (m_busRW)
m_memory.read();
break;
case 0b111: // SBC
SBC(AM_01(bbb));
SBC(AM_01(decoded.bbb));
if (m_busRW)
m_memory.read();
break;
@ -298,29 +303,29 @@ int EightBit::MOS6502::Execute(uint8_t cell) {
}
break;
case 0b10:
switch (aaa) {
switch (decoded.aaa) {
case 0b000: // ASL
ASL(AM_10(bbb, false));
ASL(AM_10(decoded.bbb, false));
if (m_busRW)
m_memory.read();
break;
case 0b001: // ROL
ROL(AM_10(bbb, false));
ROL(AM_10(decoded.bbb, false));
if (m_busRW)
m_memory.read();
break;
case 0b010: // LSR
LSR(AM_10(bbb, false));
LSR(AM_10(decoded.bbb, false));
if (m_busRW)
m_memory.read();
break;
case 0b011: // ROR
ROR(AM_10(bbb, false));
ROR(AM_10(decoded.bbb, false));
if (m_busRW)
m_memory.read();
break;
case 0b100:
switch (bbb) {
switch (decoded.bbb) {
case 0b010: // TXA
adjustNZ(A() = X());
break;
@ -328,42 +333,42 @@ int EightBit::MOS6502::Execute(uint8_t cell) {
S() = X();
break;
default: // STX
AM_10_x(bbb, false);
AM_10_x(decoded.bbb, false);
assert(m_busRW);
m_memory.write(X());
break;
}
break;
case 0b101:
switch (bbb) {
switch (decoded.bbb) {
case 0b110: // TSX
adjustNZ(X() = S());
break;
default: // LDX
LDX(AM_10_x(bbb));
adjustNZ(X() = AM_10_x(decoded.bbb));
if (m_busRW)
m_memory.read();
break;
}
break;
case 0b110:
switch (bbb) {
switch (decoded.bbb) {
case 0b010: // DEX
DEC(X());
adjustNZ(--X());
break;
default: // DEC
DEC(AM_10(bbb, false));
adjustNZ(--AM_10(decoded.bbb, false));
if (m_busRW)
m_memory.read();
break;
}
break;
case 0b111:
switch (bbb) {
switch (decoded.bbb) {
case 0b010: // NOP
break;
default: // INC
INC(AM_10(bbb, false));
adjustNZ(++AM_10(decoded.bbb, false));
if (m_busRW)
m_memory.read();
break;
@ -415,10 +420,6 @@ void EightBit::MOS6502::FetchWord(register16_t& output) {
////
void EightBit::MOS6502::DEC(uint8_t& target) {
adjustNZ(--target);
}
void EightBit::MOS6502::ROR(uint8_t& output) {
auto carry = P() & CF;
setFlag(P(), CF, output & CF);
@ -437,10 +438,6 @@ void EightBit::MOS6502::BIT(uint8_t data) {
setFlag(P(), VF, data & VF);
}
void EightBit::MOS6502::INC(uint8_t& output) {
adjustNZ(++output);
}
void EightBit::MOS6502::ROL(uint8_t& output) {
uint8_t result = (output << 1) | (P() & CF);
setFlag(P(), CF, output & Bit7);
@ -448,18 +445,10 @@ void EightBit::MOS6502::ROL(uint8_t& output) {
}
void EightBit::MOS6502::ASL(uint8_t& output) {
setFlag(P(), CF, (output & 0x80) >> 7);
setFlag(P(), CF, (output & Bit7) >> 7);
adjustNZ(output <<= 1);
}
void EightBit::MOS6502::ORA(uint8_t data) {
adjustNZ(A() |= data);
}
void EightBit::MOS6502::AND(uint8_t data) {
adjustNZ(A() &= data);
}
void EightBit::MOS6502::SBC(uint8_t data) {
if (P() & DF)
SBC_d(data);
@ -472,7 +461,7 @@ void EightBit::MOS6502::SBC_b(uint8_t data) {
difference.word = A() - data - (~P() & CF);
adjustNZ(difference.low);
setFlag(P(), VF, (A() ^ data) & (A() ^ difference.low) & 0x80);
setFlag(P(), VF, (A() ^ data) & (A() ^ difference.low) & NF);
clearFlag(P(), CF, difference.high);
A() = difference.low;
@ -486,7 +475,7 @@ void EightBit::MOS6502::SBC_d(uint8_t data) {
adjustNZ(difference.low);
setFlag(P(), VF, (A() ^ data) & (A() ^ difference.low) & 0x80);
setFlag(P(), VF, (A() ^ data) & (A() ^ difference.low) & NF);
clearFlag(P(), CF, difference.high);
auto low = (uint8_t)(lowNibble(A()) - lowNibble(data) - carry);
@ -503,10 +492,6 @@ void EightBit::MOS6502::SBC_d(uint8_t data) {
A() = promoteNibble(high) | lowNibble(low);
}
void EightBit::MOS6502::EOR(uint8_t data) {
adjustNZ(A() ^= data);
}
void EightBit::MOS6502::CMP(uint8_t first, uint8_t second) {
register16_t result;
result.word = first - second;
@ -514,18 +499,6 @@ void EightBit::MOS6502::CMP(uint8_t first, uint8_t second) {
clearFlag(P(), CF, result.high);
}
void EightBit::MOS6502::LDA(uint8_t data) {
adjustNZ(A() = data);
}
void EightBit::MOS6502::LDY(uint8_t data) {
adjustNZ(Y() = data);
}
void EightBit::MOS6502::LDX(uint8_t data) {
adjustNZ(X() = data);
}
void EightBit::MOS6502::ADC(uint8_t data) {
if (P() & DF)
ADC_d(data);
@ -539,7 +512,7 @@ void EightBit::MOS6502::ADC_b(uint8_t data) {
sum.word = A() + data + (P() & CF);
adjustNZ(sum.low);
setFlag(P(), VF, ~(A() ^ data) & (A() ^ sum.low) & 0x80);
setFlag(P(), VF, ~(A() ^ data) & (A() ^ sum.low) & NF);
setFlag(P(), CF, sum.high & CF);
A() = sum.low;
@ -558,7 +531,7 @@ void EightBit::MOS6502::ADC_d(uint8_t data) {
low += 6;
auto high = (uint8_t)(highNibble(A()) + highNibble(data) + (low > 0xf ? 1 : 0));
setFlag(P(), VF, ~(A() ^ data) & (A() ^ promoteNibble(high)) & 0x80);
setFlag(P(), VF, ~(A() ^ data) & (A() ^ promoteNibble(high)) & NF);
if (high > 9)
high += 6;
@ -602,7 +575,7 @@ void EightBit::MOS6502::JSR_abs() {
Address_Absolute();
PC().word--;
PushWord(PC());
PC() = m_memptr;
PC() = MEMPTR();
}
void EightBit::MOS6502::RTI() {
@ -617,17 +590,12 @@ void EightBit::MOS6502::RTS() {
void EightBit::MOS6502::JMP_abs() {
Address_Absolute();
PC() = m_memptr;
PC() = MEMPTR();
}
void EightBit::MOS6502::JMP_ind() {
Address_Indirect();
PC() = m_memptr;
}
void EightBit::MOS6502::JMP_absxind() {
Address_IndirectX();
PC() = m_memptr;
PC() = MEMPTR();
}
void EightBit::MOS6502::BRK() {

View File

@ -32,15 +32,8 @@ namespace EightBit {
class Memory {
public:
static uint8_t highByte(uint16_t value) {
return value >> 8;
}
static uint8_t lowByte(uint16_t value) {
return value & 0xff;
}
Memory(uint16_t addressMask);
virtual ~Memory();
// Only fired with read/write methods
Signal<AddressEventArgs> WrittenByte;
@ -68,7 +61,7 @@ namespace EightBit {
return m_locked[effective] ? placeDATA(m_bus[effective]) : referenceDATA(m_bus[effective]);
}
virtual uint16_t effectiveAddress(uint16_t address) const {
virtual int effectiveAddress(int address) const {
return address & m_addressMask;
}

View File

@ -38,11 +38,11 @@ namespace EightBit {
Bit0 = 0x1,
};
static uint8_t highNibble(uint8_t value) { return value >> 4; }
static uint8_t lowNibble(uint8_t value) { return value & Mask4; }
static int highNibble(int value) { return value >> 4; }
static int lowNibble(int value) { return value & Mask4; }
static uint8_t promoteNibble(uint8_t value) { return value << 4; }
static uint8_t demoteNibble(uint8_t value) { return highNibble(value); }
static int promoteNibble(int value) { return value << 4; }
static int demoteNibble(int value) { return highNibble(value); }
const Memory& getMemory() const { return m_memory; }

View File

@ -14,6 +14,9 @@ EightBit::Memory::Memory(uint16_t addressMask)
m_data = &(m_bus[m_address.word]);
}
EightBit::Memory::~Memory() {
}
uint8_t EightBit::Memory::peek(uint16_t address) const {
return m_bus[address];
}