First step of moving to an instruction decoder, rather than a lookup table.

Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian.Conlon 2017-07-22 23:52:58 +01:00
parent 9a264c7c06
commit 8f18a128cd
2 changed files with 383 additions and 176 deletions

View File

@ -43,17 +43,9 @@ namespace EightBit {
virtual register16_t& DE() override { return de; }
virtual register16_t& HL() override { return hl; }
bool isInterruptable() const {
return m_interrupt;
}
bool isInterruptable() const;
int interrupt(uint8_t value) {
if (isInterruptable()) {
di();
return execute(value);
}
return 0;
}
int interrupt(uint8_t value);
virtual void initialise();
int step();
@ -72,11 +64,7 @@ namespace EightBit {
int execute(uint8_t opcode);
int execute(const Instruction& instruction) {
cycles = 0;
instruction.vector();
return cycles + instruction.count;
}
int execute(const Instruction& instruction);
void adjustReservedFlags() {
F() = (F() | Bit1) & ~(Bit5 | Bit3);
@ -90,15 +78,9 @@ namespace EightBit {
clearFlag(f, AC, calculateHalfCarrySub(before, value, calculation));
}
static void increment(uint8_t& f, uint8_t& operand) {
adjustSZP<Intel8080>(f, ++operand);
clearFlag(f, AC, lowNibble(operand));
}
static void increment(uint8_t& f, uint8_t& operand);
static void decrement(uint8_t& f, uint8_t& operand) {
adjustSZP<Intel8080>(f, --operand);
setFlag(f, AC, lowNibble(operand) != Mask4);
}
static void decrement(uint8_t& f, uint8_t& operand);
static Instruction INS(instruction_t method, AddressingMode mode, std::string disassembly, int cycles);
Instruction UNKNOWN();
@ -107,68 +89,18 @@ namespace EightBit {
//
void compare(uint8_t& f, uint8_t check, uint8_t value) {
subtract(f, check, value);
}
void compare(uint8_t& f, uint8_t check, uint8_t value);
void anda(uint8_t value);
void ora(uint8_t value);
void xra(uint8_t value);
void anda(uint8_t value) {
auto& a = A();
auto& f = F();
setFlag(f, AC, (a | value) & Bit3);
clearFlag(f, CF);
adjustSZP<Intel8080>(f, a &= value);
}
void add(uint8_t value, int carry = 0);
void adc(uint8_t value);
void ora(uint8_t value) {
auto& f = F();
clearFlag(f, AC | CF);
adjustSZP<Intel8080>(f, A() |= value);
}
void dad(uint16_t value);
void xra(uint8_t value) {
auto& f = F();
clearFlag(f, AC | CF);
adjustSZP<Intel8080>(f, A() ^= value);
}
void add(uint8_t value, int carry = 0) {
auto& a = A();
auto& f = F();
register16_t sum;
sum.word = a + value + carry;
adjustAuxiliaryCarryAdd(f, a, value, sum.word);
a = sum.low;
setFlag(f, CF, sum.word & Bit8);
adjustSZP<Intel8080>(f, a);
}
void adc(uint8_t value) {
add(value, F() & CF);
}
void dad(uint16_t value) {
auto& f = F();
auto sum = HL().word + value;
setFlag(f, CF, sum & Bit16);
HL().word = sum;
}
void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0) {
register16_t result;
result.word = operand - value - carry;
adjustAuxiliaryCarrySub(f, operand, value, result.word);
operand = result.low;
setFlag(f, CF, result.word & Bit8);
adjustSZP<Intel8080>(f, operand);
}
void sbb(uint8_t value) {
subtract(F(), A(), value, F() & CF);
}
void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0);
void sbb(uint8_t value);
void mov_m_r(uint8_t value) {
m_memory.ADDRESS() = HL();
@ -332,16 +264,7 @@ namespace EightBit {
adjustReservedFlags();
}
void xhtl() {
m_memory.ADDRESS() = SP();
MEMPTR().low = m_memory.reference();
m_memory.reference() = L();
L() = MEMPTR().low;
m_memory.ADDRESS().word++;
MEMPTR().high = m_memory.reference();
m_memory.reference() = H();
H() = MEMPTR().high;
}
void xhtl();
void sphl() {
SP() = HL();
@ -356,56 +279,51 @@ namespace EightBit {
// jump
void jmp() { jumpConditional(true); }
void jmp();
void jc() { jumpConditional(F() & CF); }
void jnc() { jumpConditional(!(F() & CF)); }
void jc();
void jnc();
void jz() { jumpConditional(F() & ZF); }
void jnz() { jumpConditional(!(F() & ZF)); }
void jz();
void jnz();
void jpe() { jumpConditional(F() & PF); }
void jpo() { jumpConditional(!(F() & PF)); }
void jpe();
void jpo();
void jm() { jumpConditional(F() & SF); }
void jp() { jumpConditional(!(F() & SF)); }
void jm();
void jp();
void pchl() {
PC() = HL();
}
void pchl();
// call
void callDirect() {
fetchWord();
call();
}
void callDirect();
void cc() { if (callConditional(F() & CF)) cycles += 6; }
void cnc() { if (callConditional(!(F() & CF))) cycles += 6; }
void cc();
void cnc();
void cpe() { if (callConditional(F() & PF)) cycles += 6; }
void cpo() { if (callConditional(!(F() & PF))) cycles += 6; }
void cpe();
void cpo();
void cz() { if (callConditional(F() & ZF)) cycles += 6; }
void cnz() { if (callConditional(!(F() & ZF))) cycles += 6; }
void cz();
void cnz();
void cm() { if (callConditional(F() & SF)) cycles += 6; }
void cp() { if (callConditional(!(F() & SF))) cycles += 6; }
void cm();
void cp();
// return
void rc() { if (returnConditional(F() & CF)) cycles += 6; }
void rnc() { if (returnConditional(!(F() & CF))) cycles += 6; }
void rc();
void rnc();
void rz() { if (returnConditional(F() & ZF)) cycles += 6; }
void rnz() { if (returnConditional(!(F() & ZF))) cycles += 6; }
void rz();
void rnz();
void rpe() { if (returnConditional(F() & PF)) cycles += 6; }
void rpo() { if (returnConditional(!(F() & PF))) cycles += 6; }
void rpe();
void rpo();
void rm() { if (returnConditional(F() & SF)) cycles += 6; }
void rp() { if (returnConditional(!(F() & SF))) cycles += 6; }
void rm();
void rp();
// restart
@ -591,67 +509,27 @@ namespace EightBit {
// rotate
void rlc() {
auto& a = A();
auto carry = a & Bit7;
a = (a << 1) | (carry >> 7);
setFlag(F(), CF, carry);
}
void rrc() {
auto& a = A();
auto carry = a & Bit0;
a = (a >> 1) | (carry << 7);
setFlag(F(), CF, carry);
}
void ral() {
auto& a = A();
auto& f = F();
const auto carry = f & CF;
setFlag(f, CF, a & Bit7);
a = (a << 1) | carry;
}
void rar() {
auto& a = A();
auto& f = F();
const auto carry = f & CF;
setFlag(f, CF, a & Bit0);
a = (a >> 1) | (carry << 7);
}
void rlc();
void rrc();
void ral();
void rar();
// specials
void cma() { A() ^= Mask8; }
void stc() { setFlag(F(), CF); }
void cmc() { clearFlag(F(), CF, F() & CF); }
void daa() {
const auto& a = A();
auto& f = F();
auto carry = f & CF;
uint8_t addition = 0;
if ((f & AC) || lowNibble(a) > 9) {
addition = 0x6;
}
if ((f & CF) || highNibble(a) > 9 || (highNibble(a) >= 9 && lowNibble(a) > 9)) {
addition |= 0x60;
carry = true;
}
add(addition);
setFlag(f, CF, carry);
}
void cma();
void stc();
void cmc();
void daa();
// input/output
void out() { m_ports.write(fetchByte(), A()); }
void in() { A() = m_ports.read(fetchByte()); }
void out();
void in();
// control
void ei() { m_interrupt = true; }
void di() { m_interrupt = false; }
void ei();
void di();
void nop() {}

View File

@ -62,6 +62,329 @@ void EightBit::Intel8080::initialise() {
AF().word = BC().word = DE().word = HL().word = 0;
}
#pragma region Interrupt routines
void EightBit::Intel8080::di() {
m_interrupt = false;
}
void EightBit::Intel8080::ei() {
m_interrupt = true;
}
int EightBit::Intel8080::interrupt(uint8_t value) {
if (isInterruptable()) {
di();
return execute(value);
}
return 0;
}
bool EightBit::Intel8080::isInterruptable() const {
return m_interrupt;
}
#pragma endregion Interrupt routines
#pragma region Flag manipulation helpers
void EightBit::Intel8080::increment(uint8_t& f, uint8_t& operand) {
adjustSZP<Intel8080>(f, ++operand);
clearFlag(f, AC, lowNibble(operand));
}
void EightBit::Intel8080::decrement(uint8_t& f, uint8_t& operand) {
adjustSZP<Intel8080>(f, --operand);
setFlag(f, AC, lowNibble(operand) != Mask4);
}
#pragma endregion Flag manipulation helpers
#pragma region PC manipulation: call/ret/jp/jr
void EightBit::Intel8080::jmp() {
jumpConditional(true);
}
void EightBit::Intel8080::jc() {
jumpConditional(F() & CF);
}
void EightBit::Intel8080::jnc() {
jumpConditional(!(F() & CF));
}
void EightBit::Intel8080::jz() {
jumpConditional(F() & ZF);
}
void EightBit::Intel8080::jnz() {
jumpConditional(!(F() & ZF));
}
void EightBit::Intel8080::jpe() {
jumpConditional(F() & PF);
}
void EightBit::Intel8080::jpo() {
jumpConditional(!(F() & PF));
}
void EightBit::Intel8080::jm() {
jumpConditional(F() & SF);
}
void EightBit::Intel8080::jp() {
jumpConditional(!(F() & SF));
}
void EightBit::Intel8080::pchl() {
PC() = HL();
}
void EightBit::Intel8080::rc() {
if (returnConditional(F() & CF))
cycles += 6;
}
void EightBit::Intel8080::rnc() {
if (returnConditional(!(F() & CF)))
cycles += 6;
}
void EightBit::Intel8080::rz() {
if (returnConditional(F() & ZF))
cycles += 6;
}
void EightBit::Intel8080::rnz() {
if (returnConditional(!(F() & ZF)))
cycles += 6;
}
void EightBit::Intel8080::rpe() {
if (returnConditional(F() & PF))
cycles += 6;
}
void EightBit::Intel8080::rpo() {
if (returnConditional(!(F() & PF)))
cycles += 6;
}
void EightBit::Intel8080::rm() {
if (returnConditional(F() & SF))
cycles += 6;
}
void EightBit::Intel8080::rp() {
if (returnConditional(!(F() & SF)))
cycles += 6;
}
void EightBit::Intel8080::callDirect() {
fetchWord();
call();
}
void EightBit::Intel8080::cc() {
if (callConditional(F() & CF))
cycles += 6;
}
void EightBit::Intel8080::cnc() {
if (callConditional(!(F() & CF)))
cycles += 6;
}
void EightBit::Intel8080::cpe() {
if (callConditional(F() & PF))
cycles += 6;
}
void EightBit::Intel8080::cpo() {
if (callConditional(!(F() & PF)))
cycles += 6;
}
void EightBit::Intel8080::cz() {
if (callConditional(F() & ZF))
cycles += 6;
}
void EightBit::Intel8080::cnz() {
if (callConditional(!(F() & ZF)))
cycles += 6;
}
void EightBit::Intel8080::cm() {
if (callConditional(F() & SF))
cycles += 6;
}
void EightBit::Intel8080::cp() {
if (callConditional(!(F() & SF)))
cycles += 6;
}
#pragma endregion PC manipulation: call/ret/jp/jr
#pragma region 16-bit arithmetic
void EightBit::Intel8080::dad(uint16_t value) {
auto& f = F();
auto sum = HL().word + value;
setFlag(f, CF, sum & Bit16);
HL().word = sum;
}
#pragma endregion 16-bit arithmetic
#pragma region ALU
void EightBit::Intel8080::add(uint8_t value, int carry) {
auto& a = A();
auto& f = F();
register16_t sum;
sum.word = a + value + carry;
adjustAuxiliaryCarryAdd(f, a, value, sum.word);
a = sum.low;
setFlag(f, CF, sum.word & Bit8);
adjustSZP<Intel8080>(f, a);
}
void EightBit::Intel8080::adc(uint8_t value) {
add(value, F() & CF);
}
void EightBit::Intel8080::subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry) {
register16_t result;
result.word = operand - value - carry;
adjustAuxiliaryCarrySub(f, operand, value, result.word);
operand = result.low;
setFlag(f, CF, result.word & Bit8);
adjustSZP<Intel8080>(f, operand);
}
void EightBit::Intel8080::sbb(uint8_t value) {
subtract(F(), A(), value, F() & CF);
}
void EightBit::Intel8080::anda(uint8_t value) {
auto& a = A();
auto& f = F();
setFlag(f, AC, (a | value) & Bit3);
clearFlag(f, CF);
adjustSZP<Intel8080>(f, a &= value);
}
void EightBit::Intel8080::xra(uint8_t value) {
auto& f = F();
clearFlag(f, AC | CF);
adjustSZP<Intel8080>(f, A() ^= value);
}
void EightBit::Intel8080::ora(uint8_t value) {
auto& f = F();
clearFlag(f, AC | CF);
adjustSZP<Intel8080>(f, A() |= value);
}
void EightBit::Intel8080::compare(uint8_t& f, uint8_t check, uint8_t value) {
subtract(f, check, value);
}
#pragma endregion ALU
#pragma region Shift and rotate
void EightBit::Intel8080::rlc() {
auto& a = A();
auto carry = a & Bit7;
a = (a << 1) | (carry >> 7);
setFlag(F(), CF, carry);
}
void EightBit::Intel8080::rrc() {
auto& a = A();
auto carry = a & Bit0;
a = (a >> 1) | (carry << 7);
setFlag(F(), CF, carry);
}
void EightBit::Intel8080::ral() {
auto& a = A();
auto& f = F();
const auto carry = f & CF;
setFlag(f, CF, a & Bit7);
a = (a << 1) | carry;
}
void EightBit::Intel8080::rar() {
auto& a = A();
auto& f = F();
const auto carry = f & CF;
setFlag(f, CF, a & Bit0);
a = (a >> 1) | (carry << 7);
}
#pragma endregion Shift and rotate
#pragma region Miscellaneous instructions
void EightBit::Intel8080::daa() {
const auto& a = A();
auto& f = F();
auto carry = f & CF;
uint8_t addition = 0;
if ((f & AC) || lowNibble(a) > 9) {
addition = 0x6;
}
if ((f & CF) || highNibble(a) > 9 || (highNibble(a) >= 9 && lowNibble(a) > 9)) {
addition |= 0x60;
carry = true;
}
add(addition);
setFlag(f, CF, carry);
}
void EightBit::Intel8080::cma() {
A() ^= Mask8;
}
void EightBit::Intel8080::stc() {
setFlag(F(), CF);
}
void EightBit::Intel8080::cmc() {
clearFlag(F(), CF, F() & CF);
}
void EightBit::Intel8080::xhtl() {
m_memory.ADDRESS() = SP();
MEMPTR().low = m_memory.reference();
m_memory.reference() = L();
L() = MEMPTR().low;
m_memory.ADDRESS().word++;
MEMPTR().high = m_memory.reference();
m_memory.reference() = H();
H() = MEMPTR().high;
}
#pragma endregion Miscellaneous instructions
void EightBit::Intel8080::out() {
m_ports.write(fetchByte(), A());
}
void EightBit::Intel8080::in() {
A() = m_ports.read(fetchByte());
}
int EightBit::Intel8080::step() {
ExecutingInstruction.fire(*this);
return execute(fetchByte());
@ -72,6 +395,12 @@ int EightBit::Intel8080::execute(uint8_t opcode) {
return execute(instruction);
}
int EightBit::Intel8080::execute(const Instruction& instruction) {
cycles = 0;
instruction.vector();
return cycles + instruction.count;
}
//
void EightBit::Intel8080::___() {