Some more rationalisation of processor execution/stepping strategies.

Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian.Conlon 2017-08-30 23:17:34 +01:00
parent 5fe3d458df
commit e70686c5de
11 changed files with 150 additions and 127 deletions

View File

@ -21,9 +21,9 @@ namespace EightBit {
Signal<Intel8080> ExecutingInstruction;
bool isInterruptable() const;
int interrupt(uint8_t value);
virtual int execute(uint8_t opcode);
int step();
virtual register16_t& AF() override {
@ -32,17 +32,9 @@ namespace EightBit {
return af;
}
virtual register16_t& BC() override {
return bc;
}
virtual register16_t& DE() override {
return de;
}
virtual register16_t& HL() override {
return hl;
}
virtual register16_t& BC() override { return bc; }
virtual register16_t& DE() override { return de; }
virtual register16_t& HL() override { return hl; }
virtual void initialise();
@ -159,11 +151,9 @@ namespace EightBit {
static void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0);
virtual int execute(uint8_t opcode);
void execute(int x, int y, int z, int p, int q);
static void increment(uint8_t& f, uint8_t& operand);
static void decrement(uint8_t& f, uint8_t& operand);
bool returnConditionalFlag(uint8_t& f, int flag);

View File

@ -1,8 +1,7 @@
#include "stdafx.h"
#include "Intel8080.h"
#include "Memory.h"
#include "Disassembler.h"
#pragma region Reset and initialisation
EightBit::Intel8080::Intel8080(Memory& memory, InputOutput& ports)
: IntelProcessor(memory),
@ -16,6 +15,8 @@ void EightBit::Intel8080::initialise() {
AF().word = BC().word = DE().word = HL().word = 0;
}
#pragma endregion Reset and initialisation
#pragma region Interrupt routines
void EightBit::Intel8080::di() {
@ -279,12 +280,18 @@ void EightBit::Intel8080::in() {
#pragma endregion I/O instructions
#pragma region Controlled instruction execution
int EightBit::Intel8080::step() {
ExecutingInstruction.fire(*this);
cycles = 0;
return fetchExecute();
}
#pragma endregion Controlled instruction execution
#pragma region Instruction decode and execution
int EightBit::Intel8080::execute(uint8_t opcode) {
const auto& decoded = getDecodedOpcode(opcode);
@ -639,3 +646,5 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
break;
}
}
#pragma endregion Instruction decode and execution

View File

@ -21,31 +21,14 @@ namespace 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();
virtual register16_t& AF() override {
af.low &= 0xf0;
return af;
}
virtual register16_t& BC() override {
return bc;
}
virtual register16_t& DE() override {
return de;
}
virtual register16_t& HL() override {
return hl;
}
virtual register16_t& BC() override { return bc; }
virtual register16_t& DE() override { return de; }
virtual register16_t& HL() override { return hl; }
virtual void reset();
virtual void initialise();
@ -53,23 +36,11 @@ namespace EightBit {
static int framesPerSecond() { return 60; }
static int cyclesPerFrame() { return cyclesPerSecond() / framesPerSecond(); }
int runRasterLines() {
m_bus.resetLY();
int cycles = 0;
for (int line = 0; line < Display::RasterHeight; ++line)
cycles += runRasterLine();
return cycles;
}
int runRasterLines();
int runRasterLine();
int runVerticalBlankLines();
int runVerticalBlankLines() {
m_bus.triggerInterrupt(Bus::Interrupts::VerticalBlank);
int cycles = 0;
for (int line = 0; line < (Bus::TotalLineCount - Display::RasterHeight); ++line)
cycles += runRasterLine();
return cycles;
}
int run(int limit);
int singleStep();
protected:
virtual int execute(uint8_t opcode);
@ -84,21 +55,14 @@ namespace EightBit {
register16_t hl;
bool m_ime;
bool m_stopped;
bool m_prefixCB;
bool m_stopped;
static int cyclesPerSecond() { return 4 * 1024 * 1024; }
static int cyclesPerLine() { return cyclesPerFrame() / Bus::TotalLineCount; }
int runRasterLine() {
auto cycles = run(cyclesPerLine());
m_bus.incrementLY();
if ((m_bus.peekRegister(Bus::STAT) & Processor::Bit6) && (m_bus.peekRegister(Bus::LYC) == m_bus.peekRegister(Bus::LY)))
m_bus.triggerInterrupt(Bus::Interrupts::DisplayControlStatus);
return cycles;
}
bool& IME() { return m_ime; }
uint8_t R(int r, uint8_t& a) {
switch (r) {
@ -203,6 +167,13 @@ namespace EightBit {
static void increment(uint8_t& f, uint8_t& operand);
static void decrement(uint8_t& f, uint8_t& operand);
void stop() { m_stopped = true; }
void start() { m_stopped = false; }
bool stopped() const { return m_stopped; }
void di();
void ei();
void reti();
bool jrConditionalFlag(uint8_t& f, int flag);

View File

@ -2,13 +2,14 @@
#include "LR35902.h"
// based on http://www.z80.info/decoding.htm
// Half carry flag help from https://github.com/oubiwann/z80
#pragma region Reset and initialisation
EightBit::LR35902::LR35902(Bus& memory)
: IntelProcessor(memory),
m_bus(memory),
m_ime(false),
m_prefixCB(false) {
: IntelProcessor(memory),
m_bus(memory),
m_ime(false),
m_prefixCB(false) {
}
void EightBit::LR35902::reset() {
@ -29,6 +30,8 @@ void EightBit::LR35902::initialise() {
m_prefixCB = false;
}
#pragma endregion Reset and initialisation
#pragma region Interrupt routines
void EightBit::LR35902::di() {
@ -328,40 +331,66 @@ void EightBit::LR35902::ccf(uint8_t& a, uint8_t& f) {
#pragma endregion Miscellaneous instructions
int EightBit::LR35902::run(int limit) {
#pragma region Controlled instruction execution
int EightBit::LR35902::runRasterLines() {
m_bus.resetLY();
int cycles = 0;
for (int line = 0; line < Display::RasterHeight; ++line)
cycles += runRasterLine();
return cycles;
}
int EightBit::LR35902::runRasterLine() {
auto cycles = run(cyclesPerLine());
m_bus.incrementLY();
if ((m_bus.peekRegister(Bus::STAT) & Processor::Bit6) && (m_bus.peekRegister(Bus::LYC) == m_bus.peekRegister(Bus::LY)))
m_bus.triggerInterrupt(Bus::Interrupts::DisplayControlStatus);
return cycles;
}
int EightBit::LR35902::runVerticalBlankLines() {
m_bus.triggerInterrupt(Bus::Interrupts::VerticalBlank);
int cycles = 0;
for (int line = 0; line < (Bus::TotalLineCount - Display::RasterHeight); ++line)
cycles += runRasterLine();
return cycles;
}
int EightBit::LR35902::singleStep() {
int current = 0;
do {
auto interruptEnable = m_bus.peekRegister(Bus::IE);
auto interruptFlags = m_bus.peekRegister(Bus::IF);
auto ime = IME();
auto masked = interruptEnable & interruptFlags;
if (masked) {
if (ime) {
m_bus.pokeRegister(Bus::IF, 0);
} else {
if (isHalted())
proceed();
}
}
auto interruptEnable = m_bus.peekRegister(Bus::IE);
auto interruptFlags = m_bus.peekRegister(Bus::IF);
auto ime = IME();
if (ime && (masked & Bus::Interrupts::VerticalBlank)) {
current += interrupt(0x40);
} else if (ime && (masked & Bus::Interrupts::DisplayControlStatus)) {
current += interrupt(0x48);
} else if (ime && (masked & Bus::Interrupts::TimerOverflow)) {
current += interrupt(0x50);
} else if (ime && (masked & Bus::Interrupts::SerialTransfer)) {
current += interrupt(0x58);
} else if (ime && (masked & Bus::Interrupts::Keypad)) {
current += interrupt(0x60);
auto masked = interruptEnable & interruptFlags;
if (masked) {
if (ime) {
m_bus.pokeRegister(Bus::IF, 0);
} else {
current += isHalted() ? 1 : step();
if (isHalted())
proceed();
}
}
m_bus.checkTimers(current);
if (ime && (masked & Bus::Interrupts::VerticalBlank)) {
current += interrupt(0x40);
} else if (ime && (masked & Bus::Interrupts::DisplayControlStatus)) {
current += interrupt(0x48);
} else if (ime && (masked & Bus::Interrupts::TimerOverflow)) {
current += interrupt(0x50);
} else if (ime && (masked & Bus::Interrupts::SerialTransfer)) {
current += interrupt(0x58);
} else if (ime && (masked & Bus::Interrupts::Keypad)) {
current += interrupt(0x60);
} else {
current += isHalted() ? 1 : step();
}
m_bus.checkTimers(current);
} while (current < limit);
return current;
}
@ -372,6 +401,10 @@ int EightBit::LR35902::step() {
return fetchExecute();
}
#pragma endregion Controlled instruction execution
#pragma region Instruction decode and execution
int EightBit::LR35902::execute(uint8_t opcode) {
const auto& decoded = getDecodedOpcode(opcode);
@ -864,4 +897,6 @@ void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) {
}
break;
}
}
}
#pragma endregion Instruction decode and execution

View File

@ -42,11 +42,16 @@ namespace EightBit {
};
MOS6502(Memory& memory);
virtual ~MOS6502();
Signal<MOS6502> ExecutingInstruction;
Signal<MOS6502> ExecutedInstruction;
virtual void triggerIRQ();
virtual void triggerNMI();
virtual int execute(uint8_t opcode);
int step();
uint8_t& X() { return x; }
uint8_t& Y() { return y; }
uint8_t& A() { return a; }
@ -54,23 +59,8 @@ namespace EightBit {
uint8_t& P() { return p; }
virtual void initialise();
virtual int step();
virtual void reset();
virtual void triggerIRQ();
virtual void triggerNMI();
void getWord(register16_t& output);
void getWord(uint16_t offset, register16_t& output);
void getWord(const register16_t& offset, register16_t& output);
protected:
virtual void interrupt(uint16_t vector);
virtual int execute(uint8_t opcode);
private:
void adjustZero(uint8_t datum) { clearFlag(P(), ZF, datum); }
void adjustNegative(uint8_t datum) { setFlag(P(), NF, datum & NF); }
@ -80,9 +70,15 @@ namespace EightBit {
adjustNegative(datum);
}
void getWord(register16_t& output);
void getWord(uint16_t offset, register16_t& output);
void getWord(const register16_t& offset, register16_t& output);
virtual void push(uint8_t value) override;
virtual uint8_t pop() override;
void interrupt(uint16_t vector);
#pragma region 6502 addressing modes
#pragma region Addresses

View File

@ -24,9 +24,6 @@ EightBit::MOS6502::MOS6502(Memory& memory)
};
}
EightBit::MOS6502::~MOS6502() {
}
void EightBit::MOS6502::initialise() {
Processor::initialise();

View File

@ -326,10 +326,7 @@ void Fuse::TestRunner::run() {
initialise();
auto allowedCycles = m_test.registerState.tstates;
try {
auto cycles = 0;
do {
cycles += m_cpu.step();
} while (allowedCycles > cycles);
m_cpu.run(allowedCycles);
check();
} catch (std::logic_error& error) {
m_unimplemented = true;

View File

@ -46,9 +46,6 @@ namespace EightBit {
Signal<Z80> ExecutingInstruction;
void di();
void ei();
int interruptMaskable(uint8_t value) { return interrupt(true, value); }
int interruptMaskable() { return interruptMaskable(0); }
int interruptNonMaskable() { return interrupt(false, 0); }
@ -102,6 +99,12 @@ namespace EightBit {
virtual void initialise();
protected:
virtual int fetchExecute() override {
M1() = true;
return IntelProcessor::fetchExecute();
}
private:
InputOutput& m_ports;
enum { BC_IDX, DE_IDX, HL_IDX };
@ -132,11 +135,6 @@ namespace EightBit {
int8_t m_displacement;
bool m_displaced;
virtual int fetchExecute() override{
M1() = true;
return IntelProcessor::fetchExecute();
}
uint16_t displacedAddress() {
assert(m_displaced);
return MEMPTR().word = (m_prefixDD ? IX() : IY()).word + m_displacement;
@ -326,6 +324,9 @@ namespace EightBit {
static void increment(uint8_t& f, uint8_t& operand);
static void decrement(uint8_t& f, uint8_t& operand);
void di();
void ei();
void retn();
void reti();

View File

@ -2,7 +2,8 @@
#include "Z80.h"
// based on http://www.z80.info/decoding.htm
// Half carry flag help from https://github.com/oubiwann/z80
#pragma region Reset and initialisation
EightBit::Z80::Z80(Memory& memory, InputOutput& ports)
: IntelProcessor(memory),
@ -63,6 +64,8 @@ void EightBit::Z80::initialise() {
m_prefixFD = false;
}
#pragma endregion Reset and initialisation
#pragma region Interrupt routines
void EightBit::Z80::di() {
@ -748,6 +751,8 @@ void EightBit::Z80::readPort() {
#pragma endregion I/O instructions
#pragma region Controlled instruction execution
int EightBit::Z80::step() {
ExecutingInstruction.fire(*this);
m_displaced = m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false;
@ -755,6 +760,10 @@ int EightBit::Z80::step() {
return fetchExecute();
}
#pragma endregion Controlled instruction execution
#pragma region Instruction decode and execution
int EightBit::Z80::execute(uint8_t opcode) {
if (!M1())
@ -1547,4 +1556,6 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
}
break;
}
}
}
#pragma endregion Instruction decode and execution

View File

@ -65,6 +65,10 @@ namespace EightBit {
void reset();
virtual int run(int limit);
virtual int singleStep();
virtual int step() = 0;
virtual int execute(uint8_t opcode) = 0;
protected:

View File

@ -15,3 +15,15 @@ void EightBit::Processor::reset() {
void EightBit::Processor::initialise() {
reset();
}
int EightBit::Processor::run(int limit) {
int current = 0;
do {
current += singleStep();
} while (current < limit);
return current;
}
int EightBit::Processor::singleStep() {
return step();
}