2017-06-04 20:38:34 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <functional>
|
2017-08-07 20:02:31 +00:00
|
|
|
|
#include <cassert>
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
2017-09-06 23:58:56 +00:00
|
|
|
|
#include <Bus.h>
|
|
|
|
|
#include <Processor.h>
|
|
|
|
|
#include <Signal.h>
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
2017-07-02 21:03:33 +00:00
|
|
|
|
namespace EightBit {
|
2017-12-25 23:34:56 +00:00
|
|
|
|
class MOS6502 : public Processor {
|
2017-07-02 21:03:33 +00:00
|
|
|
|
public:
|
2017-07-10 14:51:33 +00:00
|
|
|
|
enum StatusBits {
|
2017-07-17 12:46:06 +00:00
|
|
|
|
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
|
2017-07-10 14:51:33 +00:00
|
|
|
|
};
|
|
|
|
|
|
2017-09-06 23:58:56 +00:00
|
|
|
|
MOS6502(Bus& bus);
|
2017-07-02 21:03:33 +00:00
|
|
|
|
|
|
|
|
|
Signal<MOS6502> ExecutingInstruction;
|
2017-07-05 16:46:02 +00:00
|
|
|
|
Signal<MOS6502> ExecutedInstruction;
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
2017-12-10 21:41:48 +00:00
|
|
|
|
virtual int execute(uint8_t opcode) final;
|
|
|
|
|
virtual int step() final;
|
2018-01-18 17:50:15 +00:00
|
|
|
|
virtual void powerOn() override;
|
2017-08-30 22:17:34 +00:00
|
|
|
|
|
2017-07-07 08:24:58 +00:00
|
|
|
|
uint8_t& X() { return x; }
|
|
|
|
|
uint8_t& Y() { return y; }
|
|
|
|
|
uint8_t& A() { return a; }
|
|
|
|
|
uint8_t& S() { return s; }
|
2017-07-10 14:51:33 +00:00
|
|
|
|
uint8_t& P() { return p; }
|
2017-07-02 21:03:33 +00:00
|
|
|
|
|
2018-01-12 20:13:35 +00:00
|
|
|
|
PinLevel& SO() { return m_soLine; } // In
|
|
|
|
|
|
2017-12-10 21:41:48 +00:00
|
|
|
|
protected:
|
|
|
|
|
virtual void reset() final;
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
2018-01-01 21:05:42 +00:00
|
|
|
|
virtual uint8_t SUB(uint8_t operand, uint8_t data, int borrow = 0);
|
|
|
|
|
uint8_t SBC(uint8_t operand, uint8_t data);
|
|
|
|
|
uint8_t SUB_b(uint8_t operand, uint8_t data, int borrow);
|
|
|
|
|
uint8_t SUB_d(uint8_t operand, uint8_t data, int borrow);
|
2017-12-25 23:34:56 +00:00
|
|
|
|
|
2018-01-02 21:20:47 +00:00
|
|
|
|
virtual uint8_t ADD(uint8_t operand, uint8_t data, int carry = 0);
|
|
|
|
|
uint8_t ADC(uint8_t operand, uint8_t data);
|
|
|
|
|
uint8_t ADD_b(uint8_t operand, uint8_t data, int carry);
|
|
|
|
|
uint8_t ADD_d(uint8_t operand, uint8_t data, int carry);
|
2017-12-25 23:34:56 +00:00
|
|
|
|
|
2017-07-02 21:03:33 +00:00
|
|
|
|
private:
|
2017-12-29 11:50:24 +00:00
|
|
|
|
void interrupt(uint8_t vector);
|
2017-12-10 21:41:48 +00:00
|
|
|
|
|
2017-07-16 09:05:49 +00:00
|
|
|
|
void adjustZero(uint8_t datum) { clearFlag(P(), ZF, datum); }
|
|
|
|
|
void adjustNegative(uint8_t datum) { setFlag(P(), NF, datum & NF); }
|
2017-07-06 20:32:52 +00:00
|
|
|
|
|
2017-07-16 09:05:49 +00:00
|
|
|
|
void adjustNZ(uint8_t datum) {
|
|
|
|
|
adjustZero(datum);
|
|
|
|
|
adjustNegative(datum);
|
2017-07-06 20:32:52 +00:00
|
|
|
|
}
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
2018-02-26 19:47:35 +00:00
|
|
|
|
register16_t getWordPaged(uint8_t page, uint8_t offset);
|
2018-01-18 21:17:45 +00:00
|
|
|
|
uint8_t getBytePaged(uint8_t page, uint8_t offset);
|
|
|
|
|
void setBytePaged(uint8_t page, uint8_t offset, uint8_t value);
|
2017-08-30 22:17:34 +00:00
|
|
|
|
|
2017-11-11 15:13:26 +00:00
|
|
|
|
virtual void push(uint8_t value) final;
|
|
|
|
|
virtual uint8_t pop() final;
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
2017-12-30 15:22:27 +00:00
|
|
|
|
// Address resolution
|
2017-07-11 20:34:01 +00:00
|
|
|
|
|
|
|
|
|
void Address_Absolute() {
|
2018-02-25 19:48:01 +00:00
|
|
|
|
MEMPTR() = fetchWord();
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Address_ZeroPage() {
|
2017-07-17 14:35:24 +00:00
|
|
|
|
MEMPTR().low = fetchByte();
|
2017-07-17 12:46:06 +00:00
|
|
|
|
MEMPTR().high = 0;
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Address_ZeroPageIndirect() {
|
|
|
|
|
Address_ZeroPage();
|
2018-02-26 19:47:35 +00:00
|
|
|
|
MEMPTR() = getWordPaged(0, MEMPTR().low);
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Address_Indirect() {
|
|
|
|
|
Address_Absolute();
|
2018-02-26 19:47:35 +00:00
|
|
|
|
MEMPTR() = getWordPaged(MEMPTR().high, MEMPTR().low);
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Address_ZeroPageX() {
|
|
|
|
|
Address_ZeroPage();
|
2017-07-17 12:46:06 +00:00
|
|
|
|
MEMPTR().low += X();
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Address_ZeroPageY() {
|
|
|
|
|
Address_ZeroPage();
|
2017-07-17 12:46:06 +00:00
|
|
|
|
MEMPTR().low += Y();
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-29 14:49:53 +00:00
|
|
|
|
bool Address_AbsoluteX() {
|
2017-07-11 20:34:01 +00:00
|
|
|
|
Address_Absolute();
|
2017-12-29 14:49:53 +00:00
|
|
|
|
const auto page = MEMPTR().high;
|
2017-07-17 12:46:06 +00:00
|
|
|
|
MEMPTR().word += X();
|
2017-12-29 14:49:53 +00:00
|
|
|
|
return MEMPTR().high != page;
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-29 14:49:53 +00:00
|
|
|
|
bool Address_AbsoluteY() {
|
2017-07-11 20:34:01 +00:00
|
|
|
|
Address_Absolute();
|
2017-12-29 14:49:53 +00:00
|
|
|
|
const auto page = MEMPTR().high;
|
2017-07-17 12:46:06 +00:00
|
|
|
|
MEMPTR().word += Y();
|
2017-12-29 14:49:53 +00:00
|
|
|
|
return MEMPTR().high != page;
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Address_IndexedIndirectX() {
|
|
|
|
|
Address_ZeroPageX();
|
2018-02-26 19:47:35 +00:00
|
|
|
|
MEMPTR() = getWordPaged(0, MEMPTR().low);
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-29 14:49:53 +00:00
|
|
|
|
bool Address_IndirectIndexedY() {
|
2017-07-11 20:34:01 +00:00
|
|
|
|
Address_ZeroPageIndirect();
|
2017-12-29 14:49:53 +00:00
|
|
|
|
const auto page = MEMPTR().high;
|
2017-07-17 12:46:06 +00:00
|
|
|
|
MEMPTR().word += Y();
|
2017-12-29 14:49:53 +00:00
|
|
|
|
return MEMPTR().high != page;
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-30 15:22:27 +00:00
|
|
|
|
// Addressing modes, read
|
2017-07-11 20:34:01 +00:00
|
|
|
|
|
2017-08-06 16:06:48 +00:00
|
|
|
|
uint8_t AM_Immediate() {
|
|
|
|
|
return fetchByte();
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-06 16:06:48 +00:00
|
|
|
|
uint8_t AM_Absolute() {
|
2017-07-11 20:34:01 +00:00
|
|
|
|
Address_Absolute();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
return BUS().read(MEMPTR());
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-06 16:06:48 +00:00
|
|
|
|
uint8_t AM_ZeroPage() {
|
2017-07-11 20:34:01 +00:00
|
|
|
|
Address_ZeroPage();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
return BUS().read(MEMPTR());
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-06 16:06:48 +00:00
|
|
|
|
uint8_t AM_AbsoluteX() {
|
2017-12-29 14:56:26 +00:00
|
|
|
|
if (UNLIKELY(Address_AbsoluteX()))
|
2017-11-03 22:05:01 +00:00
|
|
|
|
addCycle();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
return BUS().read(MEMPTR());
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-06 16:06:48 +00:00
|
|
|
|
uint8_t AM_AbsoluteY() {
|
2017-12-29 14:56:26 +00:00
|
|
|
|
if (UNLIKELY(Address_AbsoluteY()))
|
2017-11-03 22:05:01 +00:00
|
|
|
|
addCycle();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
return BUS().read(MEMPTR());
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-06 16:06:48 +00:00
|
|
|
|
uint8_t AM_ZeroPageX() {
|
2017-07-11 20:34:01 +00:00
|
|
|
|
Address_ZeroPageX();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
return BUS().read(MEMPTR());
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-06 16:06:48 +00:00
|
|
|
|
uint8_t AM_ZeroPageY() {
|
2017-07-11 20:34:01 +00:00
|
|
|
|
Address_ZeroPageY();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
return BUS().read(MEMPTR());
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-06 16:06:48 +00:00
|
|
|
|
uint8_t AM_IndexedIndirectX() {
|
2017-07-11 20:34:01 +00:00
|
|
|
|
Address_IndexedIndirectX();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
return BUS().read(MEMPTR());
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-06 16:06:48 +00:00
|
|
|
|
uint8_t AM_IndirectIndexedY() {
|
2017-12-29 14:56:26 +00:00
|
|
|
|
if (UNLIKELY(Address_IndirectIndexedY()))
|
2017-11-03 22:05:01 +00:00
|
|
|
|
addCycle();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
return BUS().read(MEMPTR());
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-30 15:22:27 +00:00
|
|
|
|
// Addressing modes, write
|
2017-08-06 16:06:48 +00:00
|
|
|
|
|
|
|
|
|
void AM_Absolute(uint8_t value) {
|
|
|
|
|
Address_Absolute();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(MEMPTR(), value);
|
2017-08-06 16:06:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AM_ZeroPage(uint8_t value) {
|
|
|
|
|
Address_ZeroPage();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(MEMPTR(), value);
|
2017-08-06 16:06:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AM_AbsoluteX(uint8_t value) {
|
|
|
|
|
Address_AbsoluteX();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(MEMPTR(), value);
|
2017-08-06 16:06:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AM_AbsoluteY(uint8_t value) {
|
|
|
|
|
Address_AbsoluteY();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(MEMPTR(), value);
|
2017-08-06 16:06:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AM_ZeroPageX(uint8_t value) {
|
|
|
|
|
Address_ZeroPageX();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(MEMPTR(), value);
|
2017-08-06 16:06:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AM_ZeroPageY(uint8_t value) {
|
|
|
|
|
Address_ZeroPageY();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(MEMPTR(), value);
|
2017-08-06 16:06:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AM_IndexedIndirectX(uint8_t value) {
|
|
|
|
|
Address_IndexedIndirectX();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(MEMPTR(), value);
|
2017-08-06 16:06:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AM_IndirectIndexedY(uint8_t value) {
|
|
|
|
|
Address_IndirectIndexedY();
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(MEMPTR(), value);
|
2017-08-06 16:06:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-30 15:22:27 +00:00
|
|
|
|
// Operations
|
2017-07-11 20:34:01 +00:00
|
|
|
|
|
2018-01-16 23:54:43 +00:00
|
|
|
|
void DCP(uint8_t value) {
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(--value);
|
2018-01-16 23:54:43 +00:00
|
|
|
|
CMP(A(), value);
|
2017-07-17 20:00:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-16 23:54:43 +00:00
|
|
|
|
void ISB(uint8_t value) {
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(++value);
|
2018-01-16 23:54:43 +00:00
|
|
|
|
A() = SBC(A(), value);
|
2017-07-17 20:00:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-16 23:54:43 +00:00
|
|
|
|
void SLO(uint8_t value) {
|
|
|
|
|
const auto result = ASL(value);
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(result);
|
2018-01-16 23:54:43 +00:00
|
|
|
|
ORA(result);
|
2017-07-17 20:00:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-16 23:54:43 +00:00
|
|
|
|
void SRE(uint8_t value) {
|
|
|
|
|
const auto result = LSR(value);
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(result);
|
2018-01-16 23:54:43 +00:00
|
|
|
|
EORA(result);
|
2017-07-17 20:00:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-16 23:54:43 +00:00
|
|
|
|
void RLA(uint8_t value) {
|
|
|
|
|
const auto result = ROL(value);
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(result);
|
2018-01-16 23:54:43 +00:00
|
|
|
|
ANDA(result);
|
2017-07-17 20:00:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-16 23:54:43 +00:00
|
|
|
|
void RRA(uint8_t value) {
|
|
|
|
|
const auto result = ROR(value);
|
2018-03-10 01:53:57 +00:00
|
|
|
|
BUS().write(result);
|
2018-01-16 23:54:43 +00:00
|
|
|
|
A() = ADC(A(), result);
|
2018-01-04 21:47:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-16 23:54:43 +00:00
|
|
|
|
void LAX(uint8_t value) {
|
|
|
|
|
adjustNZ(X() = A() = value);
|
2018-01-02 21:20:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-21 10:45:25 +00:00
|
|
|
|
void AAC(uint8_t value) {
|
|
|
|
|
ANDA(value);
|
|
|
|
|
setFlag(P(), CF, A() & Bit7);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ASR(uint8_t value) {
|
|
|
|
|
A() = LSR(A() & value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ARR(uint8_t value) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ATX(uint8_t value) {
|
|
|
|
|
ANDA(value);
|
|
|
|
|
X() = A();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AXS(uint8_t value) {
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-14 21:03:29 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
uint8_t DEC(uint8_t value) {
|
|
|
|
|
const auto result = --value;
|
|
|
|
|
adjustNZ(result);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t INC(uint8_t value) {
|
|
|
|
|
const auto result = ++value;
|
|
|
|
|
adjustNZ(result);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-04 22:46:44 +00:00
|
|
|
|
void ORA(uint8_t value) {
|
|
|
|
|
adjustNZ(A() |= value);
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-07 22:50:14 +00:00
|
|
|
|
void ANDA(uint8_t value) {
|
|
|
|
|
adjustNZ(A() &= value);
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-07 23:16:24 +00:00
|
|
|
|
void EORA(uint8_t value) {
|
|
|
|
|
adjustNZ(A() ^= value);
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-14 21:03:29 +00:00
|
|
|
|
uint8_t ROR(uint8_t value);
|
2017-07-11 20:34:01 +00:00
|
|
|
|
|
2018-01-14 21:03:29 +00:00
|
|
|
|
uint8_t LSR(uint8_t value);
|
2017-07-11 20:34:01 +00:00
|
|
|
|
|
2017-07-02 21:03:33 +00:00
|
|
|
|
void BIT(uint8_t data);
|
|
|
|
|
|
2018-01-14 21:03:29 +00:00
|
|
|
|
uint8_t ROL(uint8_t value);
|
2017-07-02 21:03:33 +00:00
|
|
|
|
|
2018-01-14 21:03:29 +00:00
|
|
|
|
uint8_t ASL(uint8_t value);
|
2017-07-02 21:03:33 +00:00
|
|
|
|
|
|
|
|
|
void CMP(uint8_t first, uint8_t second);
|
|
|
|
|
|
|
|
|
|
void Branch(int8_t displacement);
|
2017-07-14 16:22:28 +00:00
|
|
|
|
|
2017-07-02 21:03:33 +00:00
|
|
|
|
void Branch(bool flag);
|
2017-07-14 16:22:28 +00:00
|
|
|
|
|
|
|
|
|
void PHP();
|
|
|
|
|
void PLP();
|
2017-07-02 21:03:33 +00:00
|
|
|
|
|
|
|
|
|
void JSR_abs();
|
2017-07-14 16:22:28 +00:00
|
|
|
|
void RTI();
|
|
|
|
|
void RTS();
|
2017-07-02 21:03:33 +00:00
|
|
|
|
void JMP_abs();
|
|
|
|
|
void JMP_ind();
|
2017-07-14 16:22:28 +00:00
|
|
|
|
void BRK();
|
2017-07-02 21:03:33 +00:00
|
|
|
|
|
2017-12-29 11:50:24 +00:00
|
|
|
|
// All interrupt vectors are on the 0xFF page
|
|
|
|
|
const uint8_t IRQvector = 0xfe;
|
|
|
|
|
const uint8_t RSTvector = 0xfc;
|
|
|
|
|
const uint8_t NMIvector = 0xfa;
|
2017-07-02 21:03:33 +00:00
|
|
|
|
|
2018-01-18 17:50:15 +00:00
|
|
|
|
uint8_t x = 0; // index register X
|
|
|
|
|
uint8_t y = 0; // index register Y
|
|
|
|
|
uint8_t a = 0; // accumulator
|
|
|
|
|
uint8_t s = 0; // stack pointer
|
|
|
|
|
uint8_t p = 0; // processor status
|
2017-07-02 21:03:33 +00:00
|
|
|
|
|
2018-01-12 20:13:35 +00:00
|
|
|
|
PinLevel m_soLine = Low;
|
2017-07-02 21:03:33 +00:00
|
|
|
|
};
|
|
|
|
|
}
|