Add CMP implementations for the 6809 (tricky!)

Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon 2018-08-20 11:52:09 +01:00
parent fc31ae84d5
commit dad5ee8926
2 changed files with 193 additions and 35 deletions

View File

@ -78,42 +78,73 @@ namespace EightBit {
virtual void reset() final;
private:
const uint8_t RESETvector = 0xfe;
const uint8_t NMIvector = 0xfc;
const uint8_t SWIvector = 0xfa;
const uint8_t IRQvector = 0xf8;
const uint8_t FIRQvector = 0xf6;
const uint8_t SWI2vector = 0xf4;
const uint8_t SWI3vector = 0xf2;
const uint8_t RESERVEDvector = 0xf0;
const uint8_t RESETvector = 0xfe; // RESET vector
const uint8_t NMIvector = 0xfc; // NMI vector
const uint8_t SWIvector = 0xfa; // SWI vector
const uint8_t IRQvector = 0xf8; // IRQ vector
const uint8_t FIRQvector = 0xf6; // FIRQ vector
const uint8_t SWI2vector = 0xf4; // SWI2 vector
const uint8_t SWI3vector = 0xf2; // SWI3 vector
const uint8_t RESERVEDvector = 0xf0; // RESERVED vector
// Execution helpers
int executeUnprefixed(uint8_t opcode);
int execute10(uint8_t opcode);
int execute11(uint8_t opcode);
// Register selection for "indexed"
register16_t& RR(int which);
// Addressing modes
void Address_direct();
void Address_indexed();
void Address_extended();
void Address_direct(); // DP + fetched offset
void Address_indexed(); // Indexed address, complicated!
void Address_extended(); // Fetched address
// Addressing mode readers
// Single byte readers
uint8_t AM_immediate_byte();
uint8_t AM_direct_byte();
uint8_t AM_indexed_byte();
uint8_t AM_extended_byte();
// Word readers
register16_t AM_immediate_word();
register16_t AM_direct_word();
register16_t AM_indexed_word();
register16_t AM_extended_word();
void adjustZero(uint8_t datum) { clearFlag(CC(), ZF, datum); }
void adjustNegative(uint8_t datum) { setFlag(CC(), NF, datum & NF); }
void adjustNZ(uint8_t datum) {
// Flag adjustment
template<class T> void adjustZero(T datum) { clearFlag(CC(), ZF, datum); }
void adjustNegative(uint8_t datum) { setFlag(CC(), NF, datum & Bit7); }
void adjustNegative(uint16_t datum) { setFlag(CC(), NF, datum & Bit15); }
template<class T> void adjustNZ(T datum) {
adjustZero(datum);
adjustNegative(datum);
}
void adjustCarry(uint16_t datum) { setFlag(CC(), CF, datum & Bit8); } // 8-bit addition
void adjustCarry(uint32_t datum) { setFlag(CC(), CF, datum & Bit16); } // 16-bit addition
void adjustBorrow(uint16_t datum) { clearFlag(CC(), CF, datum & Bit8); } // 8-bit subtraction
void adjustBorrow(uint32_t datum) { clearFlag(CC(), CF, datum & Bit16); } // 16-bit subtraction
void adjustOverflow(uint8_t before, uint8_t data, uint8_t after) {
setFlag(CC(), VF, (before ^ data) & (before ^ after) & Bit7);
}
void adjustOverflow(uint16_t before, uint16_t data, uint16_t after) {
setFlag(CC(), VF, (before ^ data) & (before ^ after) & Bit15);
}
// Instruction implementations
void abx();
uint8_t adc(uint8_t operand, uint8_t data);
uint8_t add(uint8_t operand, uint8_t data, int carry = 0);
@ -122,6 +153,8 @@ namespace EightBit {
uint8_t asl(uint8_t operand);
uint8_t asr(uint8_t operand);
uint8_t clr();
void cmp(uint8_t operand, uint8_t data);
void cmp(register16_t operand, register16_t data);
uint8_t neg(uint8_t operand);
register16_t m_d;
@ -134,5 +167,8 @@ namespace EightBit {
uint8_t m_cc;
PinLevel m_firq;
bool m_prefix10 = false;
bool m_prefix11 = false;
};
}

View File

@ -23,12 +23,28 @@ void EightBit::mc6809::reset() {
Processor::reset();
DP() = 0; // Reestablish zero page
CC() |= (IF & FF); // Disable interrupts
m_prefix10 = m_prefix11 = false;
jump(getWordPaged(0xff, RESETvector));
}
int EightBit::mc6809::execute(uint8_t cell) {
int EightBit::mc6809::execute(uint8_t opcode) {
if (m_prefix10)
return execute10(opcode);
else if (m_prefix11)
return execute11(opcode);
return executeUnprefixed(opcode);
}
switch (cell) {
int EightBit::mc6809::executeUnprefixed(uint8_t opcode) {
ASSUME(!m_prefix10);
ASSUME(!m_prefix11);
ASSUME(cycles() == 0);
switch (opcode) {
case 0x10: m_prefix10 = true; break;
case 0x11: m_prefix11 = true; break;
// ABX
case 0x3a: addCycles(3); abx(); break; // ABX (inherent)
@ -36,13 +52,13 @@ int EightBit::mc6809::execute(uint8_t cell) {
// ADC
case 0x89: addCycles(2); A() = adc(A(), AM_immediate_byte()); break; // ADC (ADCA, immediate)
case 0x99: addCycles(4); A() = adc(A(), AM_direct_byte()); break; // ADC (ADCA, direct)
case 0xA9: addCycles(4); A() = adc(A(), AM_indexed_byte()); break; // ADC (ADCA, indexed)
case 0xB9: addCycles(4); A() = adc(A(), AM_extended_byte()); break; // ADC (ADCA, extended)
case 0xa9: addCycles(4); A() = adc(A(), AM_indexed_byte()); break; // ADC (ADCA, indexed)
case 0xb9: addCycles(4); A() = adc(A(), AM_extended_byte()); break; // ADC (ADCA, extended)
case 0xC9: addCycles(2); B() = adc(B(), AM_immediate_byte()); break; // ADC (ADCB, immediate)
case 0xD9: addCycles(4); B() = adc(B(), AM_direct_byte()); break; // ADC (ADCB, direct)
case 0xE9: addCycles(4); B() = adc(B(), AM_indexed_byte()); break; // ADC (ADCB, indexed)
case 0xF9: addCycles(4); B() = adc(B(), AM_extended_byte()); break; // ADC (ADCB, extended)
case 0xc9: addCycles(2); B() = adc(B(), AM_immediate_byte()); break; // ADC (ADCB, immediate)
case 0xd9: addCycles(4); B() = adc(B(), AM_direct_byte()); break; // ADC (ADCB, direct)
case 0xe9: addCycles(4); B() = adc(B(), AM_indexed_byte()); break; // ADC (ADCB, indexed)
case 0xf9: addCycles(4); B() = adc(B(), AM_extended_byte()); break; // ADC (ADCB, extended)
// ADD
case 0x8b: addCycles(2); A() = add(A(), AM_immediate_byte()); break; // ADD (ADDA, immediate)
@ -90,8 +106,8 @@ int EightBit::mc6809::execute(uint8_t cell) {
// BIT
case 0x85: addCycles(2); andr(A(), AM_immediate_byte()); break; // BIT (BITA, immediate)
case 0x95: addCycles(4); andr(A(), AM_direct_byte()); break; // BIT (BITA, direct)
case 0xA5: addCycles(4); andr(A(), AM_indexed_byte()); break; // BIT (BITA, indexed)
case 0xB5: addCycles(5); andr(A(), AM_extended_byte()); break; // BIT (BITA, extended)
case 0xa5: addCycles(4); andr(A(), AM_indexed_byte()); break; // BIT (BITA, indexed)
case 0xb5: addCycles(5); andr(A(), AM_extended_byte()); break; // BIT (BITA, extended)
case 0xc5: addCycles(2); andr(B(), AM_immediate_byte()); break; // BIT (BITB, immediate)
case 0xd5: addCycles(4); andr(B(), AM_direct_byte()); break; // BIT (BITB, direct)
@ -105,6 +121,26 @@ int EightBit::mc6809::execute(uint8_t cell) {
case 0x6f: addCycles(6); Address_indexed(); BUS().write(clr()); break; // CLR (CLR, indexed)
case 0x7f: addCycles(7); Address_extended(); BUS().write(clr()); break; // CLR (CLR, extended)
// CMP
// CMPA
case 0x81: addCycles(2); cmp(A(), AM_immediate_byte()); break; // CMP (CMPA, immediate)
case 0x91: addCycles(4); cmp(A(), AM_direct_byte()); break; // CMP (CMPA, direct)
case 0xa1: addCycles(4); cmp(A(), AM_indexed_byte()); break; // CMP (CMPA, indexed)
case 0xb1: addCycles(5); cmp(A(), AM_extended_byte()); break; // CMP (CMPA, extended)
// CMPB
case 0xc1: addCycles(2); cmp(B(), AM_immediate_byte()); break; // CMP (CMPB, immediate)
case 0xd1: addCycles(4); cmp(B(), AM_direct_byte()); break; // CMP (CMPB, direct)
case 0xe1: addCycles(4); cmp(B(), AM_indexed_byte()); break; // CMP (CMPB, indexed)
case 0xf1: addCycles(5); cmp(B(), AM_extended_byte()); break; // CMP (CMPB, extended)
// CMPX
case 0x8c: addCycles(4); cmp(X(), AM_immediate_word()); break; // CMP (CMPX, immediate)
case 0x9c: addCycles(6); cmp(X(), AM_direct_word()); break; // CMP (CMPX, direct)
case 0xac: addCycles(6); cmp(X(), AM_indexed_word()); break; // CMP (CMPX, indexed)
case 0xbc: addCycles(7); cmp(X(), AM_extended_word()); break; // CMP (CMPX, extended)
// NEG
case 0x00: addCycles(6); BUS().write(neg(AM_direct_byte())); break; // NEG (direct)
case 0x40: addCycles(2); A() = neg(A()); break; // NEG (NEGA, inherent)
@ -116,6 +152,74 @@ int EightBit::mc6809::execute(uint8_t cell) {
UNREACHABLE;
}
if (m_prefix10 || m_prefix11)
ASSUME(cycles() == 0);
else
ASSUME(cycles() > 0);
return cycles();
}
int EightBit::mc6809::execute10(uint8_t opcode) {
ASSUME(m_prefix10);
ASSUME(!m_prefix11);
ASSUME(cycles() == 0);
switch (opcode) {
// CMP
// CMPD
case 0x83: addCycles(5); cmp(D(), AM_immediate_word()); break; // CMP (CMPD, immediate)
case 0x93: addCycles(7); cmp(D(), AM_direct_word()); break; // CMP (CMPD, direct)
case 0xa3: addCycles(7); cmp(D(), AM_indexed_word()); break; // CMP (CMPD, indexed)
case 0xb3: addCycles(8); cmp(D(), AM_extended_word()); break; // CMP (CMPD, extended)
// CMPY
case 0x8c: addCycles(5); cmp(Y(), AM_immediate_word()); break; // CMP (CMPY, immediate)
case 0x9c: addCycles(7); cmp(Y(), AM_direct_word()); break; // CMP (CMPY, direct)
case 0xac: addCycles(7); cmp(Y(), AM_indexed_word()); break; // CMP (CMPY, indexed)
case 0xbc: addCycles(8); cmp(Y(), AM_extended_word()); break; // CMP (CMPY, extended)
default:
UNREACHABLE;
}
m_prefix10 = false;
ASSUME(cycles() > 0);
return cycles();
}
int EightBit::mc6809::execute11(uint8_t opcode) {
ASSUME(m_prefix10);
ASSUME(!m_prefix11);
ASSUME(cycles() == 0);
switch (opcode) {
// CMP
// CMPU
case 0x83: addCycles(5); cmp(U(), AM_immediate_word()); break; // CMP (CMPU, immediate)
case 0x93: addCycles(7); cmp(U(), AM_direct_word()); break; // CMP (CMPU, direct)
case 0xa3: addCycles(7); cmp(U(), AM_indexed_word()); break; // CMP (CMPU, indexed)
case 0xb3: addCycles(8); cmp(U(), AM_extended_word()); break; // CMP (CMPU, extended)
// CMPS
case 0x8c: addCycles(5); cmp(S(), AM_immediate_word()); break; // CMP (CMPS, immediate)
case 0x9c: addCycles(7); cmp(S(), AM_direct_word()); break; // CMP (CMPS, direct)
case 0xac: addCycles(7); cmp(S(), AM_indexed_word()); break; // CMP (CMPS, indexed)
case 0xbc: addCycles(8); cmp(S(), AM_extended_word()); break; // CMP (CMPS, extended)
default:
UNREACHABLE;
}
m_prefix11 = false;
ASSUME(cycles() > 0);
return cycles();
}
@ -281,23 +385,25 @@ uint8_t EightBit::mc6809::adc(uint8_t operand, uint8_t data) {
}
uint8_t EightBit::mc6809::add(uint8_t operand, uint8_t data, int carry) {
const register16_t result = operand + data + carry;
adjustNZ(result.low);
setFlag(CC(), CF, result.word & Bit8);
return result.low;
const register16_t addition = operand + data + carry;
const auto result = addition.low;
adjustNZ(result);
adjustCarry(addition.word);
adjustOverflow(operand, data, result);
return result;
}
EightBit::register16_t EightBit::mc6809::add(register16_t operand, register16_t data) {
const uint32_t addition = operand.word + data.word;
const register16_t result = addition;
setFlag(CC(), NF, result.high & Bit7);
setFlag(CC(), ZF, result.word == 0);
setFlag(CC(), CF, addition & Bit16);
const register16_t result = addition & Mask16;
adjustNZ(result.word);
adjustCarry(addition);
adjustOverflow(operand.word, data.word, result.word);
return result;
}
uint8_t EightBit::mc6809::andr(uint8_t operand, uint8_t data) {
const auto result = operand & data;
const uint8_t result = operand & data;
clearFlag(CC(), VF);
adjustNZ(result);
return result;
@ -308,7 +414,7 @@ uint8_t EightBit::mc6809::asl(uint8_t operand) {
operand <<= 1;
adjustNZ(operand);
const auto overflow = (CC() & CF) ^ ((CC() & NF) >> 3);
setFlag(CC(), overflow);
setFlag(CC(), VF, overflow);
return operand;
}
@ -324,3 +430,19 @@ uint8_t EightBit::mc6809::clr() {
setFlag(CC(), ZF);
return 0;
}
void EightBit::mc6809::cmp(const uint8_t operand, const uint8_t data) {
const register16_t difference = operand - data;
const auto result = difference.low;
adjustNZ(result);
adjustBorrow(difference.word);
adjustOverflow(operand, data, result);
}
void EightBit::mc6809::cmp(register16_t operand, register16_t data) {
const uint32_t difference = operand.word - data.word;
const register16_t result = difference & Mask16;
adjustNZ(result.word);
adjustBorrow(difference);
adjustOverflow(operand.word, data.word, result.word);
}