mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2026-10-22 07:02:37 +00:00
Broken, but kinda runs Intel 8080
This commit is contained in:
1 parent
8f4b0b1e71
commit
683fc0e878
5 files changed
+109
-120
No files matched your search
@@ -47,12 +47,9 @@ namespace EightBit {
|
||||
void handleRESET() noexcept final;
|
||||
void handleINT() noexcept final;
|
||||
|
||||
void memoryUpdate(int ticks = 1) noexcept;
|
||||
void memoryUpdate(int ticks = 1) noexcept final;
|
||||
void memoryWrite() noexcept final;
|
||||
uint8_t memoryRead() noexcept final;
|
||||
|
||||
//void busWrite() noexcept final;
|
||||
//uint8_t busRead() noexcept final;
|
||||
void memoryRead() noexcept final;
|
||||
|
||||
private:
|
||||
bool m_requestIO = false;
|
||||
@@ -65,8 +62,7 @@ namespace EightBit {
|
||||
register16_t m_de = Mask16;
|
||||
register16_t m_hl = Mask16;
|
||||
|
||||
uint8_t R(int r);
|
||||
void R(int r, uint8_t value);
|
||||
[[nodiscard]] uint8_t& R(int r, MemoryMapping::AccessLevel access = MemoryMapping::AccessLevel::ReadOnly) noexcept final;
|
||||
register16_t& RP(int rp);
|
||||
register16_t& RP2(int rp);
|
||||
|
||||
@@ -172,11 +168,11 @@ namespace EightBit {
|
||||
|
||||
void xhtl(register16_t& exchange);
|
||||
|
||||
void portWrite(uint8_t port);
|
||||
void portWrite();
|
||||
void writePort(uint8_t port) noexcept;
|
||||
void writePort() noexcept;
|
||||
|
||||
uint8_t portRead(uint8_t port);
|
||||
uint8_t portRead();
|
||||
void readPort(uint8_t port) noexcept;
|
||||
void readPort() noexcept;
|
||||
|
||||
constexpr void requestIO() noexcept { assert(!requestingMemory()); m_requestIO = true; }
|
||||
constexpr void releaseIO() noexcept { m_requestIO = false; }
|
||||
|
||||
@@ -32,8 +32,8 @@ std::string EightBit::Disassembler::state(Intel8080& cpu) {
|
||||
std::string output;
|
||||
output.reserve(80);
|
||||
output =
|
||||
"PC=" + hex(pc.word)
|
||||
+ " SP=" + hex(sp.word)
|
||||
"PC=" + hex(pc.joined)
|
||||
+ " SP=" + hex(sp.joined)
|
||||
+ " A=" + hex(a) + " F=" + flags(f)
|
||||
+ " B=" + hex(b) + " C=" + hex(c)
|
||||
+ " D=" + hex(d) + " E=" + hex(e)
|
||||
@@ -158,7 +158,7 @@ std::string EightBit::Disassembler::alu2(int which) {
|
||||
}
|
||||
|
||||
std::string EightBit::Disassembler::disassemble(Intel8080& cpu) {
|
||||
return disassemble(cpu, cpu.PC().word);
|
||||
return disassemble(cpu, cpu.PC().joined);
|
||||
}
|
||||
|
||||
std::string EightBit::Disassembler::disassemble(Intel8080& cpu, uint16_t pc) {
|
||||
@@ -177,7 +177,7 @@ std::string EightBit::Disassembler::disassemble(Intel8080& cpu, uint16_t pc) {
|
||||
auto q = (y & 1);
|
||||
|
||||
auto immediate = BUS().peek(pc + 1);
|
||||
auto absolute = cpu.peekShort(pc + 1).word;
|
||||
auto absolute = cpu.peekShort(pc + 1).joined;
|
||||
auto displacement = (int8_t)immediate;
|
||||
auto relative = pc + displacement + 2;
|
||||
auto indexedImmediate = BUS().peek(pc + 1);
|
||||
|
||||
+91
-99
@@ -37,29 +37,24 @@ EightBit::register16_t& EightBit::Intel8080::HL() noexcept {
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::memoryWrite() noexcept {
|
||||
requestMemory();
|
||||
IntelProcessor::memoryWrite();
|
||||
releaseMemory();
|
||||
memoryUpdate();
|
||||
}
|
||||
|
||||
uint8_t EightBit::Intel8080::memoryRead() noexcept {
|
||||
requestMemory();
|
||||
const auto returned = IntelProcessor::memoryRead();
|
||||
releaseMemory();
|
||||
return returned;
|
||||
void EightBit::Intel8080::memoryRead() noexcept {
|
||||
ReadingMemory.fire();
|
||||
requestMemory();
|
||||
IntelProcessor::memoryRead();
|
||||
releaseMemory();
|
||||
ReadMemory.fire();
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::busWrite() noexcept {
|
||||
requestWrite();
|
||||
IntelProcessor::busWrite();
|
||||
releaseWrite();
|
||||
}
|
||||
|
||||
uint8_t EightBit::Intel8080::busRead() noexcept {
|
||||
requestRead();
|
||||
const auto returned = IntelProcessor::busRead();
|
||||
releaseRead();
|
||||
return returned;
|
||||
void EightBit::Intel8080::memoryUpdate(int ticks) noexcept {
|
||||
WritingMemory.fire();
|
||||
tick(ticks);
|
||||
requestMemory();
|
||||
IntelProcessor::memoryWrite();
|
||||
releaseMemory();
|
||||
WrittenMemory.fire();
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::handleRESET() noexcept {
|
||||
@@ -80,7 +75,7 @@ void EightBit::Intel8080::enableInterrupts() noexcept {
|
||||
m_interruptEnable = true;
|
||||
}
|
||||
|
||||
uint8_t EightBit::Intel8080::R(const int r) {
|
||||
uint8_t& EightBit::Intel8080::R(const int r, MemoryMapping::AccessLevel access) noexcept {
|
||||
switch (r) {
|
||||
case 0b000:
|
||||
return B();
|
||||
@@ -95,7 +90,18 @@ uint8_t EightBit::Intel8080::R(const int r) {
|
||||
case 0b101:
|
||||
return L();
|
||||
case 0b110:
|
||||
return IntelProcessor::memoryRead(HL());
|
||||
BUS().ADDRESS() = HL();
|
||||
switch (access) {
|
||||
case MemoryMapping::AccessLevel::ReadOnly:
|
||||
memoryRead();
|
||||
break;
|
||||
case MemoryMapping::AccessLevel::WriteOnly:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
break;
|
||||
}
|
||||
return BUS().DATA();
|
||||
case 0b111:
|
||||
return A();
|
||||
default:
|
||||
@@ -103,37 +109,6 @@ uint8_t EightBit::Intel8080::R(const int r) {
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::R(int r, const uint8_t value) {
|
||||
switch (r) {
|
||||
case 0b000:
|
||||
B() = value;
|
||||
break;
|
||||
case 0b001:
|
||||
C() = value;
|
||||
break;
|
||||
case 0b010:
|
||||
D() = value;
|
||||
break;
|
||||
case 0b011:
|
||||
E() = value;
|
||||
break;
|
||||
case 0b100:
|
||||
H() = value;
|
||||
break;
|
||||
case 0b101:
|
||||
L() = value;
|
||||
break;
|
||||
case 0b110:
|
||||
IntelProcessor::memoryWrite(HL(), value);
|
||||
break;
|
||||
case 0b111:
|
||||
A() = value;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
EightBit::register16_t& EightBit::Intel8080::RP(const int rp) {
|
||||
switch (rp) {
|
||||
case 0b00:
|
||||
@@ -202,7 +177,7 @@ bool EightBit::Intel8080::convertCondition(int flag) noexcept {
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::add(const register16_t value) {
|
||||
const auto result = HL().word + value.word;
|
||||
const auto result = HL().joined + value.joined;
|
||||
HL() = result;
|
||||
F() = setBit(F(), CF, result & Bit16);
|
||||
}
|
||||
@@ -211,11 +186,11 @@ void EightBit::Intel8080::add(const uint8_t value, const int carry) {
|
||||
|
||||
const register16_t result = A() + value + carry;
|
||||
|
||||
adjustAuxiliaryCarryAdd(A(), value, result.word);
|
||||
adjustAuxiliaryCarryAdd(A(), value, result.joined);
|
||||
|
||||
A() = result.low;
|
||||
|
||||
setBit(CF, result.word & Bit8);
|
||||
setBit(CF, result.joined & Bit8);
|
||||
adjustSZP(A());
|
||||
}
|
||||
|
||||
@@ -230,10 +205,10 @@ uint8_t EightBit::Intel8080::subtract(const uint8_t value, const int carry) {
|
||||
const register16_t subtraction = operand - value - carry;
|
||||
const auto result = subtraction.low;
|
||||
|
||||
adjustAuxiliaryCarrySub(operand, value, subtraction.word);
|
||||
adjustAuxiliaryCarrySub(operand, value, subtraction.joined);
|
||||
|
||||
setBit(CF, subtraction.word & Bit8);
|
||||
adjustSZP(operand);
|
||||
setBit(CF, subtraction.joined & Bit8);
|
||||
adjustSZP(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -318,9 +293,8 @@ void EightBit::Intel8080::cmc() {
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::xhtl(register16_t& exchange) {
|
||||
MEMPTR().low = IntelProcessor::memoryRead(SP());
|
||||
++BUS().ADDRESS();
|
||||
MEMPTR().high = memoryRead();
|
||||
BUS().ADDRESS() = SP();
|
||||
getInto(MEMPTR());
|
||||
BUS().DATA() = exchange.high;
|
||||
exchange.high = MEMPTR().high;
|
||||
memoryUpdate(2);
|
||||
@@ -331,41 +305,38 @@ void EightBit::Intel8080::xhtl(register16_t& exchange) {
|
||||
tick(2);
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::portWrite(const uint8_t port) {
|
||||
void EightBit::Intel8080::writePort(const uint8_t port) noexcept {
|
||||
BUS().ADDRESS() = { port, port };
|
||||
BUS().DATA() = A();
|
||||
portWrite();
|
||||
writePort();
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::portWrite() {
|
||||
void EightBit::Intel8080::writePort() noexcept {
|
||||
requestIO();
|
||||
busWrite();
|
||||
releaseIO();;
|
||||
}
|
||||
|
||||
uint8_t EightBit::Intel8080::portRead(const uint8_t port) {
|
||||
void EightBit::Intel8080::readPort(const uint8_t port) noexcept {
|
||||
BUS().ADDRESS() = { port, port };
|
||||
return portRead();
|
||||
readPort();
|
||||
}
|
||||
|
||||
uint8_t EightBit::Intel8080::portRead() {
|
||||
void EightBit::Intel8080::readPort() noexcept {
|
||||
requestIO();
|
||||
const auto returned = busRead();
|
||||
releaseIO();;
|
||||
return returned;
|
||||
busRead();
|
||||
releaseIO();
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::poweredStep() noexcept {
|
||||
if (UNLIKELY(lowered(RESET()))) {
|
||||
handleRESET();
|
||||
} else if (UNLIKELY(lowered(INT()))) {
|
||||
if (m_interruptEnable) {
|
||||
handleINT();
|
||||
}
|
||||
} else if (UNLIKELY(lowered(INT()) && m_interruptEnable)) {
|
||||
handleINT();
|
||||
} else if (UNLIKELY(lowered(HALT()))) {
|
||||
Processor::execute(0); // NOP
|
||||
IntelProcessor::execute(0); // NOP
|
||||
} else {
|
||||
Processor::execute(fetchByte());
|
||||
IntelProcessor::execute(fetchInstruction());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,7 +368,7 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
case 1: // 16-bit load immediate/add
|
||||
switch (q) {
|
||||
case 0: // LD rp,nn
|
||||
RP(p) = fetchWord();
|
||||
fetchInto(RP(p));
|
||||
tick(10);
|
||||
break;
|
||||
case 1: // ADD HL,rp
|
||||
@@ -421,12 +392,13 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
tick(7);
|
||||
break;
|
||||
case 2: // LD (nn),HL
|
||||
BUS().ADDRESS() = fetchWord();
|
||||
setWord(HL());
|
||||
fetchShortAddress();
|
||||
setShort(HL());
|
||||
tick(16);
|
||||
break;
|
||||
case 3: // LD (nn),A
|
||||
BUS().ADDRESS() = fetchWord();
|
||||
fetchInto(MEMPTR());
|
||||
BUS().ADDRESS() = MEMPTR();
|
||||
IntelProcessor::memoryWrite(A());
|
||||
tick(13);
|
||||
break;
|
||||
@@ -437,21 +409,25 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
case 1:
|
||||
switch (p) {
|
||||
case 0: // LD A,(BC)
|
||||
A() = IntelProcessor::memoryRead(BC());
|
||||
readMemoryIndirect(BC());
|
||||
A() = BUS().DATA();
|
||||
tick(7);
|
||||
break;
|
||||
case 1: // LD A,(DE)
|
||||
A() = IntelProcessor::memoryRead(DE());
|
||||
readMemoryIndirect(DE());
|
||||
A() = BUS().DATA();
|
||||
tick(7);
|
||||
break;
|
||||
case 2: // LD HL,(nn)
|
||||
BUS().ADDRESS() = fetchWord();
|
||||
HL() = getShort();
|
||||
fetchShortAddress();
|
||||
getShort();
|
||||
HL() = intermediate();
|
||||
tick(16);
|
||||
break;
|
||||
case 3: // LD A,(nn)
|
||||
BUS().ADDRESS() = fetchWord();
|
||||
A() = memoryRead();
|
||||
fetchInto(MEMPTR());
|
||||
readMemoryIndirect();
|
||||
A() = BUS().DATA();
|
||||
tick(13);
|
||||
break;
|
||||
default:
|
||||
@@ -477,18 +453,19 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
break;
|
||||
case 4: { // 8-bit INC
|
||||
auto operand = R(y);
|
||||
R(y, increment(operand));
|
||||
IntelProcessor::R(y, increment(operand));
|
||||
tick(4);
|
||||
break;
|
||||
} case 5: { // 8-bit DEC
|
||||
auto operand = R(y);
|
||||
R(y, decrement(operand));
|
||||
IntelProcessor::R(y, decrement(operand));
|
||||
tick(4);
|
||||
if (UNLIKELY(y == 6))
|
||||
tick(7);
|
||||
break;
|
||||
} case 6: // 8-bit load immediate
|
||||
R(y, fetchByte());
|
||||
fetchByte();
|
||||
IntelProcessor::R(y, BUS().DATA());
|
||||
tick(7);
|
||||
if (UNLIKELY(y == 6))
|
||||
tick(3);
|
||||
@@ -532,7 +509,7 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
if (UNLIKELY(z == 6 && y == 6)) { // Exception (replaces LD (HL), (HL))
|
||||
lowerHALT();
|
||||
} else {
|
||||
R(y, R(z));
|
||||
IntelProcessor::R(y, R(z));
|
||||
if (UNLIKELY((y == 6) || (z == 6))) // M operations
|
||||
tick(3);
|
||||
}
|
||||
@@ -568,17 +545,27 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
tick(4);
|
||||
if (UNLIKELY(z == 6)) // M operations take 3 extra cycles
|
||||
tick(3);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
switch (z) {
|
||||
case 0: // Conditional return
|
||||
returnConditionalFlag(y);
|
||||
case 0: { // Conditional return
|
||||
const bool condition = convertCondition(y);
|
||||
if (condition) {
|
||||
ret();
|
||||
tick(11);
|
||||
} else {
|
||||
tick(5);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: // POP & various ops
|
||||
switch (q) {
|
||||
case 0: // POP rp2[p]
|
||||
RP2(p) = popWord();
|
||||
popInto(RP2(p));
|
||||
tick(10);
|
||||
break;
|
||||
case 1:
|
||||
@@ -606,13 +593,17 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
case 3: // Assorted operations
|
||||
switch (y) {
|
||||
case 0: // JP nn
|
||||
Processor::jump(fetchWord());
|
||||
fetchInto(MEMPTR());
|
||||
jump();
|
||||
break;
|
||||
case 2: // OUT (n),A
|
||||
portWrite(fetchByte());
|
||||
fetchByte();
|
||||
writePort(BUS().DATA());
|
||||
break;
|
||||
case 3: // IN A,(n)
|
||||
A() = portRead(fetchByte());
|
||||
fetchByte();
|
||||
readPort(BUS().DATA());
|
||||
A() = BUS().DATA();
|
||||
tick(11);
|
||||
break;
|
||||
case 4: // EX (SP),HL
|
||||
@@ -635,13 +626,13 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
case 5: // PUSH & various ops
|
||||
switch (q) {
|
||||
case 0: // PUSH rp2[p]
|
||||
pushWord(RP2(p));
|
||||
pushShort(RP2(p));
|
||||
tick(11);
|
||||
break;
|
||||
case 1:
|
||||
switch (p) {
|
||||
case 0: // CALL nn
|
||||
call(fetchWord());
|
||||
callIndirect();
|
||||
tick(17);
|
||||
break;
|
||||
}
|
||||
@@ -651,7 +642,8 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
}
|
||||
break;
|
||||
case 6: { // Operate on accumulator and immediate operand: alu[y] n
|
||||
const auto operand = fetchByte();
|
||||
fetchByte();
|
||||
auto operand = BUS().DATA();
|
||||
switch (y) {
|
||||
case 0: // ADD A,n
|
||||
add(operand);
|
||||
|
||||
@@ -52,7 +52,7 @@ void Board::initialise() noexcept {
|
||||
}
|
||||
|
||||
void Board::Cpu_ExecutingInstruction_Cpm(EightBit::EventArgs&) {
|
||||
switch (CPU().PC().word) {
|
||||
switch (CPU().PC().joined) {
|
||||
case 0x0: // CP/M warm start
|
||||
if (++m_warmstartCount == 2) {
|
||||
lowerPOWER();
|
||||
@@ -77,7 +77,7 @@ void Board::bdos() {
|
||||
break;
|
||||
}
|
||||
case 0x9:
|
||||
for (uint16_t i = CPU().DE().word; peek(i) != '$'; ++i) {
|
||||
for (uint16_t i = CPU().DE().joined; peek(i) != '$'; ++i) {
|
||||
std::cout << peek(i);
|
||||
}
|
||||
break;
|
||||
@@ -88,8 +88,8 @@ void Board::Cpu_ExecutingInstruction_Profile(EightBit::EventArgs&) {
|
||||
|
||||
const auto pc = CPU().PC();
|
||||
|
||||
m_profiler.addAddress(pc.word);
|
||||
m_profiler.addInstruction(peek(pc.word));
|
||||
m_profiler.addAddress(pc.joined);
|
||||
m_profiler.addInstruction(peek(pc.joined));
|
||||
}
|
||||
|
||||
void Board::Cpu_ExecutingInstruction_Debug(const EightBit::EventArgs&) {
|
||||
|
||||
@@ -23,8 +23,8 @@ public:
|
||||
virtual void initialise() noexcept final;
|
||||
|
||||
protected:
|
||||
virtual EightBit::MemoryMapping mapping(uint16_t address) noexcept final {
|
||||
return { m_ram, 0x0000, 0xffff, EightBit::MemoryMapping::AccessLevel::ReadWrite };
|
||||
virtual const EightBit::MemoryMapping& mapping(uint16_t address) noexcept final {
|
||||
return m_mapping;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -32,6 +32,7 @@ private:
|
||||
EightBit::Ram m_ram = 0x10000;
|
||||
EightBit::InputOutput m_ports;
|
||||
EightBit::Intel8080 m_cpu;
|
||||
EightBit::MemoryMapping m_mapping = { m_ram, 0x0000, 0xffff, EightBit::MemoryMapping::AccessLevel::ReadWrite };
|
||||
EightBit::Disassembler m_disassembler;
|
||||
EightBit::Profiler m_profiler;
|
||||
int m_warmstartCount = 0;
|
||||
|
||||
Reference in new issue
Block a user