Bring LR35902 a little more in line with the Z80 implementation.

Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian.Conlon 2017-06-09 11:42:32 +01:00
parent 1c8d842bde
commit 93bac42547
8 changed files with 511 additions and 475 deletions

View File

@ -2,105 +2,107 @@
#include "Memory.h"
class Bus : public EightBit::Memory {
public:
namespace EightBit {
class Bus : public Memory {
public:
enum {
TotalLineCount = 154
enum {
TotalLineCount = 154
};
enum {
VideoRam = 0x8000
};
enum {
BASE = 0xFF00,
// Port/Mode Registers
P1 = 0x0,
SB = 0x1,
SC = 0x2,
DIV = 0x4,
TIMA = 0x5,
TMA = 0x6,
TAC = 0x7,
// Interrupt Flags
IF = 0xF,
IE = 0xFF,
// LCD Display Registers
LCDC = 0x40,
STAT = 0x41,
SCY = 0x42,
SCX = 0x43,
LY = 0x44,
LYC = 0x45,
DMA = 0x46,
BGP = 0x47,
OBP0 = 0x48,
OBP1 = 0x49,
WY = 0x4A,
WX = 0x4B,
// Sound Registers
NR10 = 0x10,
NR11 = 0x11,
NR12 = 0x12,
NR13 = 0x13,
NR14 = 0x14,
NR21 = 0x16,
NR22 = 0x17,
NR23 = 0x18,
NR24 = 0x19,
NR30 = 0x1A,
NR31 = 0x1B,
NR32 = 0x1C,
NR33 = 0x1D,
NR34 = 0x1E,
NR41 = 0x20,
NR42 = 0x21,
NR43 = 0x22,
NR44 = 0x23,
NR50 = 0x24,
NR51 = 0x25,
NR52 = 0x26,
WPRAM_START = 0x30,
WPRAM_END = 0x3F,
// Boot rom control
BOOT_DISABLE = 0x50,
};
Bus();
void reset();
uint8_t& REG(int offset) {
ADDRESS().word = BASE + offset;
return Memory::reference();
}
void incrementLY() {
REG(LY) = (REG(LY) + 1) % TotalLineCount;
}
void resetLY() {
REG(LY) = 0;
}
void loadBootRom(const std::string& path);
bool isBootRom(uint16_t address) const {
return (address < m_boot.size()) && (peek(BASE + BOOT_DISABLE) == 0);
}
virtual uint8_t peek(uint16_t address) const;
virtual uint8_t& reference();
private:
std::array<uint8_t, 0x100> m_boot;
};
enum {
VideoRam = 0x8000
};
enum {
BASE = 0xFF00,
// Port/Mode Registers
P1 = 0x0,
SB = 0x1,
SC = 0x2,
DIV = 0x4,
TIMA = 0x5,
TMA = 0x6,
TAC = 0x7,
// Interrupt Flags
IF = 0xF,
IE = 0xFF,
// LCD Display Registers
LCDC = 0x40,
STAT = 0x41,
SCY = 0x42,
SCX = 0x43,
LY = 0x44,
LYC = 0x45,
DMA = 0x46,
BGP = 0x47,
OBP0 = 0x48,
OBP1 = 0x49,
WY = 0x4A,
WX = 0x4B,
// Sound Registers
NR10 = 0x10,
NR11 = 0x11,
NR12 = 0x12,
NR13 = 0x13,
NR14 = 0x14,
NR21 = 0x16,
NR22 = 0x17,
NR23 = 0x18,
NR24 = 0x19,
NR30 = 0x1A,
NR31 = 0x1B,
NR32 = 0x1C,
NR33 = 0x1D,
NR34 = 0x1E,
NR41 = 0x20,
NR42 = 0x21,
NR43 = 0x22,
NR44 = 0x23,
NR50 = 0x24,
NR51 = 0x25,
NR52 = 0x26,
WPRAM_START = 0x30,
WPRAM_END = 0x3F,
// Boot rom control
BOOT_DISABLE = 0x50,
};
Bus();
void reset();
uint8_t& REG(int offset) {
ADDRESS().word = BASE + offset;
return Memory::reference();
}
void incrementLY() {
REG(LY) = (REG(LY) + 1) % TotalLineCount;
}
void resetLY() {
REG(LY) = 0;
}
void loadBootRom(const std::string& path);
bool isBootRom(uint16_t address) const {
return (address < m_boot.size()) && (peek(BASE + BOOT_DISABLE) == 0);
}
virtual uint8_t peek(uint16_t address) const;
virtual uint8_t& reference();
private:
std::array<uint8_t, 0x100> m_boot;
};
}

View File

@ -3,51 +3,54 @@
#include <string>
#include <boost/format.hpp>
class LR35902;
namespace EightBit {
class Disassembler {
public:
Disassembler();
class LR35902;
static std::string state(LR35902& cpu);
std::string disassemble(LR35902& cpu);
class Disassembler {
public:
Disassembler();
static std::string flag(uint8_t value, int flag, const std::string& represents);
static std::string flags(uint8_t value);
static std::string hex(uint8_t value);
static std::string hex(uint16_t value);
static std::string binary(uint8_t value);
static std::string decimal(uint8_t value);
static std::string state(LR35902& cpu);
std::string disassemble(LR35902& cpu);
static std::string invalid(uint8_t value);
static std::string flag(uint8_t value, int flag, const std::string& represents);
static std::string flags(uint8_t value);
static std::string hex(uint8_t value);
static std::string hex(uint16_t value);
static std::string binary(uint8_t value);
static std::string decimal(uint8_t value);
private:
mutable boost::format m_formatter;
bool m_prefixCB;
static std::string invalid(uint8_t value);
void disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc);
private:
mutable boost::format m_formatter;
bool m_prefixCB;
void disassembleCB(
std::ostringstream& output,
LR35902& cpu,
uint16_t pc,
std::string& specification,
int& dumpCount,
int x, int y, int z,
int p, int q);
void disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc);
void disassembleOther(
std::ostringstream& output,
LR35902& cpu,
uint16_t pc,
std::string& specification,
int& dumpCount,
int x, int y, int z,
int p, int q);
void disassembleCB(
std::ostringstream& output,
LR35902& cpu,
uint16_t pc,
std::string& specification,
int& dumpCount,
int x, int y, int z,
int p, int q);
std::string RP(int rp) const;
std::string RP2(int rp) const;
std::string R(int r) const;
static std::string cc(int flag);
static std::string alu(int which);
};
void disassembleOther(
std::ostringstream& output,
LR35902& cpu,
uint16_t pc,
std::string& specification,
int& dumpCount,
int x, int y, int z,
int p, int q);
std::string RP(int rp) const;
std::string RP2(int rp) const;
std::string R(int r) const;
static std::string cc(int flag);
static std::string alu(int which);
};
}

View File

@ -5,226 +5,228 @@
#include "Processor.h"
#include "Bus.h"
class LR35902 : public EightBit::Processor {
public:
enum StatusBits {
ZF = Bit7,
NF = Bit6,
HC = Bit5,
CF = Bit4,
namespace EightBit {
class LR35902 : public Processor {
public:
enum StatusBits {
ZF = Bit7,
NF = Bit6,
HC = Bit5,
CF = Bit4,
};
LR35902(Bus& memory);
Signal<LR35902> ExecutingInstruction;
void stop() { m_stopped = true; }
void start() { m_stopped = false; }
bool stopped() const { return m_stopped; }
bool& IME() { return m_ime; }
void di();
void ei();
int interrupt(uint8_t value);
int execute(uint8_t opcode);
int step();
// Mutable access to processor!!
register16_t& AF() {
m_accumulatorFlag.low &= 0xf0;
return m_accumulatorFlag;
}
uint8_t& A() { return AF().high; }
uint8_t& F() { return AF().low; }
register16_t& BC() {
return m_registers[BC_IDX];
}
uint8_t& B() { return BC().high; }
uint8_t& C() { return BC().low; }
register16_t& DE() {
return m_registers[DE_IDX];
}
uint8_t& D() { return DE().high; }
uint8_t& E() { return DE().low; }
register16_t& HL() {
return m_registers[HL_IDX];
}
uint8_t& H() { return HL().high; }
uint8_t& L() { return HL().low; }
virtual void reset();
virtual void initialise();
private:
enum { BC_IDX, DE_IDX, HL_IDX };
std::array<register16_t, 3> m_registers;
register16_t m_accumulatorFlag;
bool m_ime;
bool m_prefixCB;
bool m_stopped;
std::array<bool, 8> m_halfCarryTableAdd = { { false, false, true, false, true, false, true, true } };
std::array<bool, 8> m_halfCarryTableSub = { { false, true, true, true, false, false, false, true } };
register16_t fetchWord() {
register16_t returned;
Processor::fetchWord(returned);
return returned;
}
int fetchExecute() {
return execute(fetchByte());
}
void clearFlag(int flag) { F() &= ~flag; }
void setFlag(int flag) { F() |= flag; }
void setFlag(int flag, int condition) { setFlag(flag, condition != 0); }
void setFlag(int flag, uint32_t condition) { setFlag(flag, condition != 0); }
void setFlag(int flag, bool condition) { condition ? setFlag(flag) : clearFlag(flag); }
void clearFlag(int flag, int condition) { clearFlag(flag, condition != 0); }
void clearFlag(int flag, uint32_t condition) { clearFlag(flag, condition != 0); }
void clearFlag(int flag, bool condition) { condition ? clearFlag(flag) : setFlag(flag); }
uint8_t& R(int r) {
switch (r) {
case 0:
return B();
case 1:
return C();
case 2:
return D();
case 3:
return E();
case 4:
return H();
case 5:
return L();
case 6:
m_memory.ADDRESS() = HL();
return m_memory.reference();
case 7:
return A();
}
throw std::logic_error("Unhandled registry mechanism");
}
register16_t& RP(int rp) {
switch (rp) {
case 3:
return sp;
default:
return m_registers[rp];
}
}
register16_t& RP2(int rp) {
switch (rp) {
case 3:
return AF();
default:
return m_registers[rp];
}
}
int buildHalfCarryIndex(uint8_t before, uint8_t value, int calculation) {
return ((before & 0x88) >> 1) | ((value & 0x88) >> 2) | ((calculation & 0x88) >> 3);
}
void adjustHalfCarryAdd(uint8_t before, uint8_t value, int calculation) {
auto index = buildHalfCarryIndex(before, value, calculation);
setFlag(HC, m_halfCarryTableAdd[index & 0x7]);
}
void adjustHalfCarrySub(uint8_t before, uint8_t value, int calculation) {
auto index = buildHalfCarryIndex(before, value, calculation);
setFlag(HC, m_halfCarryTableSub[index & 0x7]);
}
void executeCB(int x, int y, int z, int p, int q);
void executeOther(int x, int y, int z, int p, int q);
void adjustZero(uint8_t value);
void postIncrement(uint8_t value);
void postDecrement(uint8_t value);
void restart(uint8_t address);
void jrConditional(int conditional);
void jrConditionalFlag(int flag);
void ret();
void reti();
void returnConditional(int condition);
void returnConditionalFlag(int flag);
void jumpConditional(int condition);
void jumpConditionalFlag(int flag);
void call(uint16_t address);
void callConditional(uint16_t address, int condition);
void callConditionalFlag(uint16_t address, int flag);
uint16_t sbc(uint16_t value);
uint16_t adc(uint16_t value);
uint16_t add(uint16_t value);
void sub(uint8_t& operand, uint8_t value, bool carry);
void sub(uint8_t& operand, uint8_t value);
void sbc(uint8_t& operand, uint8_t value);
void add(uint8_t& operand, uint8_t value, bool carry);
void add(uint8_t& operand, uint8_t value);
void adc(uint8_t& operand, uint8_t value);
void andr(uint8_t& operand, uint8_t value);
void anda(uint8_t value);
void xora(uint8_t value);
void ora(uint8_t value);
void compare(uint8_t value);
void rlca();
void rrca();
void rla();
void rra();
void rlc(uint8_t& operand);
void rrc(uint8_t& operand);
void rl(uint8_t& operand);
void rr(uint8_t& operand);
void sla(uint8_t& operand);
void sra(uint8_t& operand);
void srl(uint8_t& operand);
void bit(int n, uint8_t& operand);
void res(int n, uint8_t& operand);
void set(int nit, uint8_t& operand);
void daa();
void scf();
void ccf();
void cpl();
void swap(uint8_t& operand);
};
LR35902(Bus& memory);
EightBit::Signal<LR35902> ExecutingInstruction;
void stop() { m_stopped = true; }
void start() { m_stopped = false; }
bool stopped() const { return m_stopped; }
bool& IME() { return m_ime; }
void di();
void ei();
int interrupt(uint8_t value);
int execute(uint8_t opcode);
int step();
// Mutable access to processor!!
EightBit::register16_t& AF() {
m_accumulatorFlag.low &= 0xf0;
return m_accumulatorFlag;
}
uint8_t& A() { return AF().high; }
uint8_t& F() { return AF().low; }
EightBit::register16_t& BC() {
return m_registers[BC_IDX];
}
uint8_t& B() { return BC().high; }
uint8_t& C() { return BC().low; }
EightBit::register16_t& DE() {
return m_registers[DE_IDX];
}
uint8_t& D() { return DE().high; }
uint8_t& E() { return DE().low; }
EightBit::register16_t& HL() {
return m_registers[HL_IDX];
}
uint8_t& H() { return HL().high; }
uint8_t& L() { return HL().low; }
virtual void reset();
virtual void initialise();
private:
enum { BC_IDX, DE_IDX, HL_IDX };
std::array<EightBit::register16_t, 3> m_registers;
EightBit::register16_t m_accumulatorFlag;
bool m_ime;
bool m_prefixCB;
bool m_stopped;
std::array<bool, 8> m_halfCarryTableAdd = { { false, false, true, false, true, false, true, true } };
std::array<bool, 8> m_halfCarryTableSub = { { false, true, true, true, false, false, false, true } };
EightBit::register16_t fetchWord() {
EightBit::register16_t returned;
Processor::fetchWord(returned);
return returned;
}
int fetchExecute() {
return execute(fetchByte());
}
void clearFlag(int flag) { F() &= ~flag; }
void setFlag(int flag) { F() |= flag; }
void setFlag(int flag, int condition) { setFlag(flag, condition != 0); }
void setFlag(int flag, uint32_t condition) { setFlag(flag, condition != 0); }
void setFlag(int flag, bool condition) { condition ? setFlag(flag) : clearFlag(flag); }
void clearFlag(int flag, int condition) { clearFlag(flag, condition != 0); }
void clearFlag(int flag, uint32_t condition) { clearFlag(flag, condition != 0); }
void clearFlag(int flag, bool condition) { condition ? clearFlag(flag) : setFlag(flag); }
uint8_t& R(int r) {
switch (r) {
case 0:
return B();
case 1:
return C();
case 2:
return D();
case 3:
return E();
case 4:
return H();
case 5:
return L();
case 6:
m_memory.ADDRESS() = HL();
return m_memory.reference();
case 7:
return A();
}
throw std::logic_error("Unhandled registry mechanism");
}
EightBit::register16_t& RP(int rp) {
switch (rp) {
case 3:
return sp;
default:
return m_registers[rp];
}
}
EightBit::register16_t& RP2(int rp) {
switch (rp) {
case 3:
return AF();
default:
return m_registers[rp];
}
}
int buildHalfCarryIndex(uint8_t before, uint8_t value, int calculation) {
return ((before & 0x88) >> 1) | ((value & 0x88) >> 2) | ((calculation & 0x88) >> 3);
}
void adjustHalfCarryAdd(uint8_t before, uint8_t value, int calculation) {
auto index = buildHalfCarryIndex(before, value, calculation);
setFlag(HC, m_halfCarryTableAdd[index & 0x7]);
}
void adjustHalfCarrySub(uint8_t before, uint8_t value, int calculation) {
auto index = buildHalfCarryIndex(before, value, calculation);
setFlag(HC, m_halfCarryTableSub[index & 0x7]);
}
void executeCB(int x, int y, int z, int p, int q);
void executeOther(int x, int y, int z, int p, int q);
void adjustZero(uint8_t value);
void postIncrement(uint8_t value);
void postDecrement(uint8_t value);
void restart(uint8_t address);
void jrConditional(int conditional);
void jrConditionalFlag(int flag);
void ret();
void reti();
void returnConditional(int condition);
void returnConditionalFlag(int flag);
void jumpConditional(int condition);
void jumpConditionalFlag(int flag);
void call(uint16_t address);
void callConditional(uint16_t address, int condition);
void callConditionalFlag(uint16_t address, int flag);
uint16_t sbc(uint16_t value);
uint16_t adc(uint16_t value);
uint16_t add(uint16_t value);
void sub(uint8_t& operand, uint8_t value, bool carry);
void sub(uint8_t& operand, uint8_t value);
void sbc(uint8_t& operand, uint8_t value);
void add(uint8_t& operand, uint8_t value, bool carry);
void add(uint8_t& operand, uint8_t value);
void adc(uint8_t& operand, uint8_t value);
void andr(uint8_t& operand, uint8_t value);
void anda(uint8_t value);
void xora(uint8_t value);
void ora(uint8_t value);
void compare(uint8_t value);
void rlca();
void rrca();
void rla();
void rra();
void rlc(uint8_t& operand);
void rrc(uint8_t& operand);
void rl(uint8_t& operand);
void rr(uint8_t& operand);
void sla(uint8_t& operand);
void sra(uint8_t& operand);
void srl(uint8_t& operand);
void bit(int n, uint8_t& operand);
void res(int n, uint8_t& operand);
void set(int nit, uint8_t& operand);
void daa();
void scf();
void ccf();
void cpl();
void swap(uint8_t& operand);
};
}

View File

@ -5,24 +5,26 @@
#include "Disassembler.h"
class LR35902;
namespace EightBit {
class Profiler {
public:
Profiler(LR35902& cpu);
class LR35902;
void add(uint16_t address, uint8_t instruction);
class Profiler {
public:
Profiler(LR35902& cpu);
void dump() const;
void add(uint16_t address, uint8_t instruction);
private:
std::array<uint64_t, 0x100> m_instructions;
std::array<uint64_t, 0x10000> m_addresses;
LR35902& m_cpu;
void dump() const;
Disassembler m_disassembler;
private:
std::array<uint64_t, 0x100> m_instructions;
std::array<uint64_t, 0x10000> m_addresses;
LR35902& m_cpu;
void dumpInstructionProfiles() const;
void dumpAddressProfiles() const;
};
Disassembler m_disassembler;
void dumpInstructionProfiles() const;
void dumpAddressProfiles() const;
};
}

View File

@ -1,30 +1,30 @@
#include "stdafx.h"
#include "Bus.h"
Bus::Bus()
EightBit::Bus::Bus()
: Memory(0xffff) {
}
void Bus::reset() {
void EightBit::Bus::reset() {
REG(NR52) = 0xf1;
REG(LCDC) = 0x91;
}
void Bus::loadBootRom(const std::string& path) {
void EightBit::Bus::loadBootRom(const std::string& path) {
auto size = loadMemory(path, 0);
if (size != 0x100)
throw std::runtime_error("Incorrectly sized boot ROM");
std::copy_n(m_bus.cbegin(), size, m_boot.begin());
}
uint8_t& Bus::reference() {
uint8_t& EightBit::Bus::reference() {
auto effective = effectiveAddress(ADDRESS().word);
if (isBootRom(effective))
return placeDATA(m_boot[effective]);
return Memory::reference();
}
uint8_t Bus::peek(uint16_t address) const {
uint8_t EightBit::Bus::peek(uint16_t address) const {
auto effective = effectiveAddress(address);
if (isBootRom(effective))
return m_boot[effective];

View File

@ -9,12 +9,12 @@
#include "LR35902.h"
#include "StatusFlags.h"
Disassembler::Disassembler() {
EightBit::Disassembler::Disassembler() {
// Disable exceptions where too many format arguments are available
m_formatter.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
}
std::string Disassembler::state(LR35902& cpu) {
std::string EightBit::Disassembler::state(EightBit::LR35902& cpu) {
auto pc = cpu.getProgramCounter();
auto sp = cpu.getStackPointer();
@ -45,7 +45,7 @@ std::string Disassembler::state(LR35902& cpu) {
return output.str();
}
std::string Disassembler::RP(int rp) const {
std::string EightBit::Disassembler::RP(int rp) const {
switch (rp) {
case 0:
return "BC";
@ -59,7 +59,7 @@ std::string Disassembler::RP(int rp) const {
throw std::logic_error("Unhandled register pair");
}
std::string Disassembler::RP2(int rp) const {
std::string EightBit::Disassembler::RP2(int rp) const {
switch (rp) {
case 0:
return "BC";
@ -73,7 +73,7 @@ std::string Disassembler::RP2(int rp) const {
throw std::logic_error("Unhandled register pair");
}
std::string Disassembler::R(int r) const {
std::string EightBit::Disassembler::R(int r) const {
switch (r) {
case 0:
return "B";
@ -95,7 +95,7 @@ std::string Disassembler::R(int r) const {
throw std::logic_error("Unhandled register");
}
std::string Disassembler::cc(int flag) {
std::string EightBit::Disassembler::cc(int flag) {
switch (flag) {
case 0:
return "NZ";
@ -117,7 +117,7 @@ std::string Disassembler::cc(int flag) {
throw std::logic_error("Unhandled condition");
}
std::string Disassembler::alu(int which) {
std::string EightBit::Disassembler::alu(int which) {
switch (which) {
case 0: // ADD A,n
return "ADD";
@ -139,14 +139,14 @@ std::string Disassembler::alu(int which) {
throw std::logic_error("Unhandled alu operation");
}
std::string Disassembler::disassemble(LR35902& cpu) {
std::string EightBit::Disassembler::disassemble(LR35902& cpu) {
m_prefixCB = false;
std::ostringstream output;
disassemble(output, cpu, cpu.getProgramCounter().word);
return output.str();
}
void Disassembler::disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc) {
void EightBit::Disassembler::disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc) {
auto& memory = cpu.getMemory();
auto opcode = memory.peek(pc);
@ -190,7 +190,7 @@ void Disassembler::disassemble(std::ostringstream& output, LR35902& cpu, uint16_
output << m_formatter % (int)immediate % (int)absolute % relative % (int)displacement % indexedImmediate;
}
void Disassembler::disassembleCB(
void EightBit::Disassembler::disassembleCB(
std::ostringstream& output,
LR35902& cpu,
uint16_t pc,
@ -240,7 +240,7 @@ void Disassembler::disassembleCB(
}
}
void Disassembler::disassembleOther(
void EightBit::Disassembler::disassembleOther(
std::ostringstream& output,
LR35902& cpu,
uint16_t pc,
@ -504,13 +504,13 @@ void Disassembler::disassembleOther(
}
}
std::string Disassembler::flag(uint8_t value, int flag, const std::string& represents) {
std::string EightBit::Disassembler::flag(uint8_t value, int flag, const std::string& represents) {
std::ostringstream output;
output << (value & flag ? represents : "-");
return output.str();
}
std::string Disassembler::flags(uint8_t value) {
std::string EightBit::Disassembler::flags(uint8_t value) {
std::ostringstream output;
output
<< flag(value, LR35902::ZF, "Z")
@ -524,31 +524,31 @@ std::string Disassembler::flags(uint8_t value) {
return output.str();
}
std::string Disassembler::hex(uint8_t value) {
std::string EightBit::Disassembler::hex(uint8_t value) {
std::ostringstream output;
output << std::hex << std::setw(2) << std::setfill('0') << (int)value;
return output.str();
}
std::string Disassembler::hex(uint16_t value) {
std::string EightBit::Disassembler::hex(uint16_t value) {
std::ostringstream output;
output << std::hex << std::setw(4) << std::setfill('0') << (int)value;
return output.str();
}
std::string Disassembler::binary(uint8_t value) {
std::string EightBit::Disassembler::binary(uint8_t value) {
std::ostringstream output;
output << std::bitset<8>(value);
return output.str();
}
std::string Disassembler::decimal(uint8_t value) {
std::string EightBit::Disassembler::decimal(uint8_t value) {
std::ostringstream output;
output << (int)value;
return output.str();
}
std::string Disassembler::invalid(uint8_t value) {
std::string EightBit::Disassembler::invalid(uint8_t value) {
std::ostringstream output;
output << "Invalid instruction: " << hex(value) << "(" << binary(value) << ")";
return output.str();

View File

@ -4,19 +4,19 @@
// based on http://www.z80.info/decoding.htm
// Half carry flag help from https://github.com/oubiwann/z80
LR35902::LR35902(Bus& memory)
EightBit::LR35902::LR35902(Bus& memory)
: Processor(memory),
m_ime(false),
m_prefixCB(false) {
}
void LR35902::reset() {
void EightBit::LR35902::reset() {
Processor::reset();
sp.word = 0xfffe;
di();
}
void LR35902::initialise() {
void EightBit::LR35902::initialise() {
Processor::initialise();
@ -28,42 +28,54 @@ void LR35902::initialise() {
m_prefixCB = false;
}
void LR35902::di() {
#pragma region Interrupt routines
void EightBit::LR35902::di() {
IME() = false;
}
void LR35902::ei() {
void EightBit::LR35902::ei() {
IME() = true;
}
int LR35902::interrupt(uint8_t value) {
int EightBit::LR35902::interrupt(uint8_t value) {
cycles = 0;
di();
restart(value);
return 4;
}
void LR35902::adjustZero(uint8_t value) {
#pragma endregion Interrupt routines
#pragma region Flag manipulation helpers
void EightBit::LR35902::adjustZero(uint8_t value) {
clearFlag(ZF, value);
}
void LR35902::postIncrement(uint8_t value) {
void EightBit::LR35902::postIncrement(uint8_t value) {
adjustZero(value);
clearFlag(NF);
clearFlag(HC, lowNibble(value));
}
void LR35902::postDecrement(uint8_t value) {
void EightBit::LR35902::postDecrement(uint8_t value) {
adjustZero(value);
setFlag(NF);
clearFlag(HC, lowNibble(value + 1));
}
void LR35902::restart(uint8_t address) {
#pragma endregion Flag manipulation helpers
#pragma region PC manipulation: call/ret/jp/jr
void EightBit::LR35902::restart(uint8_t address) {
pushWord(pc);
pc.word = address;
pc.low = address;
pc.high = 0;
}
void LR35902::jrConditional(int conditional) {
void EightBit::LR35902::jrConditional(int conditional) {
auto offset = (int8_t)fetchByte();
if (conditional) {
pc.word += offset;
@ -71,7 +83,7 @@ void LR35902::jrConditional(int conditional) {
}
}
void LR35902::jrConditionalFlag(int flag) {
void EightBit::LR35902::jrConditionalFlag(int flag) {
switch (flag) {
case 0: // NZ
jrConditional(!(F() & ZF));
@ -94,7 +106,7 @@ void LR35902::jrConditionalFlag(int flag) {
}
}
void LR35902::jumpConditional(int conditional) {
void EightBit::LR35902::jumpConditional(int conditional) {
auto address = fetchWord();
if (conditional) {
pc = address;
@ -102,7 +114,7 @@ void LR35902::jumpConditional(int conditional) {
}
}
void LR35902::jumpConditionalFlag(int flag) {
void EightBit::LR35902::jumpConditionalFlag(int flag) {
switch (flag) {
case 0: // NZ
jumpConditional(!(F() & ZF));
@ -138,23 +150,23 @@ void LR35902::jumpConditionalFlag(int flag) {
}
}
void LR35902::ret() {
void EightBit::LR35902::ret() {
popWord(pc);
}
void LR35902::reti() {
void EightBit::LR35902::reti() {
ret();
ei();
}
void LR35902::returnConditional(int condition) {
void EightBit::LR35902::returnConditional(int condition) {
if (condition) {
ret();
cycles += 3;
}
}
void LR35902::returnConditionalFlag(int flag) {
void EightBit::LR35902::returnConditionalFlag(int flag) {
switch (flag) {
case 0: // NZ
returnConditional(!(F() & ZF));
@ -199,19 +211,19 @@ void LR35902::returnConditionalFlag(int flag) {
}
}
void LR35902::call(uint16_t address) {
void EightBit::LR35902::call(uint16_t address) {
pushWord(pc);
pc.word = address;
}
void LR35902::callConditional(uint16_t address, int condition) {
void EightBit::LR35902::callConditional(uint16_t address, int condition) {
if (condition) {
call(address);
cycles += 3;
}
}
void LR35902::callConditionalFlag(uint16_t address, int flag) {
void EightBit::LR35902::callConditionalFlag(uint16_t address, int flag) {
switch (flag) {
case 0: // NZ
callConditional(address, !(F() & ZF));
@ -234,18 +246,22 @@ void LR35902::callConditionalFlag(uint16_t address, int flag) {
}
}
uint16_t LR35902::sbc(uint16_t value) {
#pragma endregion PC manipulation: call/ret/jp/jr
#pragma region 16-bit arithmetic
uint16_t EightBit::LR35902::sbc(uint16_t value) {
auto hl = RP(HL_IDX);
auto high = hl.high;
auto highValue = EightBit::Memory::highByte(value);
auto highValue = Memory::highByte(value);
auto applyCarry = F() & CF;
uint32_t result = (int)hl.word - (int)value;
if (applyCarry)
--result;
auto highResult = EightBit::Memory::highByte(result);
auto highResult = Memory::highByte(result);
adjustZero(result);
adjustHalfCarrySub(high, highValue, highResult);
@ -256,18 +272,18 @@ uint16_t LR35902::sbc(uint16_t value) {
return result;
}
uint16_t LR35902::adc(uint16_t value) {
uint16_t EightBit::LR35902::adc(uint16_t value) {
auto hl = RP(HL_IDX);
auto high = hl.high;
auto highValue = EightBit::Memory::highByte(value);
auto highValue = Memory::highByte(value);
auto applyCarry = F() & CF;
uint32_t result = (int)hl.word + (int)value;
if (applyCarry)
++result;
auto highResult = EightBit::Memory::highByte(result);
auto highResult = Memory::highByte(result);
adjustZero(result);
adjustHalfCarryAdd(high, highValue, highResult);
@ -278,16 +294,16 @@ uint16_t LR35902::adc(uint16_t value) {
return result;
}
uint16_t LR35902::add(uint16_t value) {
uint16_t EightBit::LR35902::add(uint16_t value) {
auto hl = RP(HL_IDX);
auto high = hl.high;
auto highValue = EightBit::Memory::highByte(value);
auto highValue = Memory::highByte(value);
uint32_t result = (int)hl.word + (int)value;
auto highResult = EightBit::Memory::highByte(result);
auto highResult = Memory::highByte(result);
clearFlag(NF);
setFlag(CF, result & Bit16);
@ -296,7 +312,11 @@ uint16_t LR35902::add(uint16_t value) {
return result;
}
void LR35902::sub(uint8_t& operand, uint8_t value, bool carry) {
#pragma endregion 16-bit arithmetic
#pragma region ALU
void EightBit::LR35902::sub(uint8_t& operand, uint8_t value, bool carry) {
auto before = operand;
@ -304,7 +324,7 @@ void LR35902::sub(uint8_t& operand, uint8_t value, bool carry) {
if (carry && (F() & CF))
--result;
operand = EightBit::Memory::lowByte(result);
operand = Memory::lowByte(result);
adjustZero(operand);
adjustHalfCarrySub(before, value, result);
@ -312,15 +332,15 @@ void LR35902::sub(uint8_t& operand, uint8_t value, bool carry) {
setFlag(CF, result & Bit8);
}
void LR35902::sbc(uint8_t& operand, uint8_t value) {
void EightBit::LR35902::sbc(uint8_t& operand, uint8_t value) {
sub(operand, value, true);
}
void LR35902::sub(uint8_t& operand, uint8_t value) {
void EightBit::LR35902::sub(uint8_t& operand, uint8_t value) {
sub(operand, value, false);
}
void LR35902::add(uint8_t& operand, uint8_t value, bool carry) {
void EightBit::LR35902::add(uint8_t& operand, uint8_t value, bool carry) {
auto before = operand;
@ -328,7 +348,7 @@ void LR35902::add(uint8_t& operand, uint8_t value, bool carry) {
if (carry && (F() & CF))
++result;
operand = EightBit::Memory::lowByte(result);
operand = Memory::lowByte(result);
adjustZero(operand);
adjustHalfCarryAdd(before, value, result);
@ -336,47 +356,49 @@ void LR35902::add(uint8_t& operand, uint8_t value, bool carry) {
setFlag(CF, result & Bit8);
}
void LR35902::adc(uint8_t& operand, uint8_t value) {
void EightBit::LR35902::adc(uint8_t& operand, uint8_t value) {
add(operand, value, true);
}
void LR35902::add(uint8_t& operand, uint8_t value) {
void EightBit::LR35902::add(uint8_t& operand, uint8_t value) {
add(operand, value, false);
}
//
void LR35902::andr(uint8_t& operand, uint8_t value) {
void EightBit::LR35902::andr(uint8_t& operand, uint8_t value) {
setFlag(HC);
clearFlag(CF | NF);
operand &= value;
adjustZero(operand);
}
void LR35902::anda(uint8_t value) {
void EightBit::LR35902::anda(uint8_t value) {
andr(A(), value);
}
void LR35902::xora(uint8_t value) {
void EightBit::LR35902::xora(uint8_t value) {
clearFlag(HC | CF | NF);
A() ^= value;
adjustZero(A());
}
void LR35902::ora(uint8_t value) {
void EightBit::LR35902::ora(uint8_t value) {
clearFlag(HC | CF | NF);
A() |= value;
adjustZero(A());
}
void LR35902::compare(uint8_t value) {
void EightBit::LR35902::compare(uint8_t value) {
auto check = A();
sub(check, value);
}
//
#pragma endregion ALU
void LR35902::rlc(uint8_t& operand) {
#pragma region Shift and rotate
void EightBit::LR35902::rlc(uint8_t& operand) {
auto carry = operand & Bit7;
operand <<= 1;
setFlag(CF, carry);
@ -385,7 +407,7 @@ void LR35902::rlc(uint8_t& operand) {
adjustZero(operand);
}
void LR35902::rrc(uint8_t& operand) {
void EightBit::LR35902::rrc(uint8_t& operand) {
auto carry = operand & Bit0;
operand >>= 1;
carry ? operand |= Bit7 : operand &= ~Bit7;
@ -394,7 +416,7 @@ void LR35902::rrc(uint8_t& operand) {
adjustZero(operand);
}
void LR35902::rl(uint8_t& operand) {
void EightBit::LR35902::rl(uint8_t& operand) {
auto oldCarry = F() & CF;
auto newCarry = operand & Bit7;
operand <<= 1;
@ -404,7 +426,7 @@ void LR35902::rl(uint8_t& operand) {
adjustZero(operand);
}
void LR35902::rr(uint8_t& operand) {
void EightBit::LR35902::rr(uint8_t& operand) {
auto oldCarry = F() & CF;
auto newCarry = operand & Bit0;
operand >>= 1;
@ -416,7 +438,7 @@ void LR35902::rr(uint8_t& operand) {
//
void LR35902::sla(uint8_t& operand) {
void EightBit::LR35902::sla(uint8_t& operand) {
auto newCarry = operand & Bit7;
operand <<= 1;
setFlag(CF, newCarry);
@ -424,7 +446,7 @@ void LR35902::sla(uint8_t& operand) {
adjustZero(operand);
}
void LR35902::sra(uint8_t& operand) {
void EightBit::LR35902::sra(uint8_t& operand) {
auto new7 = operand & Bit7;
auto newCarry = operand & Bit0;
operand >>= 1;
@ -434,7 +456,7 @@ void LR35902::sra(uint8_t& operand) {
adjustZero(operand);
}
void LR35902::srl(uint8_t& operand) {
void EightBit::LR35902::srl(uint8_t& operand) {
auto newCarry = operand & Bit0;
operand >>= 1;
operand &= ~Bit7; // clear bit 7
@ -445,44 +467,48 @@ void LR35902::srl(uint8_t& operand) {
//
void LR35902::rlca() {
void EightBit::LR35902::rlca() {
rlc(A());
}
void LR35902::rrca() {
void EightBit::LR35902::rrca() {
rrc(A());
}
void LR35902::rla() {
void EightBit::LR35902::rla() {
rl(A());
}
void LR35902::rra() {
void EightBit::LR35902::rra() {
rr(A());
}
//
#pragma endregion Shift and rotate
void LR35902::bit(int n, uint8_t& operand) {
#pragma region BIT/SET/RES
void EightBit::LR35902::bit(int n, uint8_t& operand) {
auto carry = F() & CF;
uint8_t discarded = operand;
andr(discarded, 1 << n);
setFlag(CF, carry);
}
void LR35902::res(int n, uint8_t& operand) {
void EightBit::LR35902::res(int n, uint8_t& operand) {
auto bit = 1 << n;
operand &= ~bit;
}
void LR35902::set(int n, uint8_t& operand) {
void EightBit::LR35902::set(int n, uint8_t& operand) {
auto bit = 1 << n;
operand |= bit;
}
//
#pragma endregion BIT/SET/RES
void LR35902::daa() {
#pragma region Miscellaneous instructions
void EightBit::LR35902::daa() {
uint8_t a = A();
@ -508,23 +534,23 @@ void LR35902::daa() {
A() = a;
}
void LR35902::cpl() {
void EightBit::LR35902::cpl() {
A() = ~A();
setFlag(HC | NF);
}
void LR35902::scf() {
void EightBit::LR35902::scf() {
setFlag(CF);
clearFlag(HC | NF);
}
void LR35902::ccf() {
void EightBit::LR35902::ccf() {
auto carry = F() & CF;
clearFlag(CF, carry);
clearFlag(NF | HC);
}
void LR35902::swap(uint8_t& operand) {
void EightBit::LR35902::swap(uint8_t& operand) {
auto low = lowNibble(operand);
auto high = highNibble(operand);
operand = promoteNibble(low) | demoteNibble(high);
@ -532,13 +558,16 @@ void LR35902::swap(uint8_t& operand) {
clearFlag(NF | HC | CF);
}
int LR35902::step() {
#pragma endregion Miscellaneous instructions
int EightBit::LR35902::step() {
ExecutingInstruction.fire(*this);
m_prefixCB = false;
cycles = 0;
return fetchExecute();
}
int LR35902::execute(uint8_t opcode) {
int EightBit::LR35902::execute(uint8_t opcode) {
auto x = (opcode & 0b11000000) >> 6;
auto y = (opcode & 0b111000) >> 3;
@ -547,8 +576,6 @@ int LR35902::execute(uint8_t opcode) {
auto p = (y & 0b110) >> 1;
auto q = (y & 1);
cycles = 0;
if (m_prefixCB)
executeCB(x, y, z, p, q);
else
@ -560,7 +587,7 @@ int LR35902::execute(uint8_t opcode) {
return cycles * 4;
}
void LR35902::executeCB(int x, int y, int z, int p, int q) {
void EightBit::LR35902::executeCB(int x, int y, int z, int p, int q) {
switch (x) {
case 0: // rot[y] r[z]
switch (y) {
@ -615,7 +642,7 @@ void LR35902::executeCB(int x, int y, int z, int p, int q) {
}
}
void LR35902::executeOther(int x, int y, int z, int p, int q) {
void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) {
switch (x) {
case 0:
switch (z) {

View File

@ -2,13 +2,13 @@
#include "Profiler.h"
#include "LR35902.h"
Profiler::Profiler(LR35902& cpu)
EightBit::Profiler::Profiler(LR35902& cpu)
: m_cpu(cpu) {
std::fill(m_instructions.begin(), m_instructions.end(), 0);
std::fill(m_addresses.begin(), m_addresses.end(), 0);
}
void Profiler::add(uint16_t address, uint8_t instruction) {
void EightBit::Profiler::add(uint16_t address, uint8_t instruction) {
m_instructions[instruction]++;
@ -19,12 +19,12 @@ void Profiler::add(uint16_t address, uint8_t instruction) {
m_addresses[address]++;
}
void Profiler::dump() const {
void EightBit::Profiler::dump() const {
dumpInstructionProfiles();
dumpAddressProfiles();
}
void Profiler::dumpInstructionProfiles() const {
void EightBit::Profiler::dumpInstructionProfiles() const {
std::cout << "** instructions" << std::endl;
for (int i = 0; i < 0x100; ++i) {
auto count = m_instructions[i];
@ -33,7 +33,7 @@ void Profiler::dumpInstructionProfiles() const {
}
}
void Profiler::dumpAddressProfiles() const {
void EightBit::Profiler::dumpAddressProfiles() const {
std::cout << "** addresses" << std::endl;
for (int i = 0; i < 0x10000; ++i) {
auto count = m_addresses[i];