diff --git a/MC6809/inc/mc6809.h b/MC6809/inc/mc6809.h index a241d57..860cb19 100644 --- a/MC6809/inc/mc6809.h +++ b/MC6809/inc/mc6809.h @@ -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 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 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; }; } \ No newline at end of file diff --git a/MC6809/src/mc6809.cpp b/MC6809/src/mc6809.cpp index 561f8e1..84e104e 100644 --- a/MC6809/src/mc6809.cpp +++ b/MC6809/src/mc6809.cpp @@ -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); +}