diff --git a/Intel8080/documentation/1481550148_8080.pdf b/Intel8080/documentation/1481550148_8080.pdf new file mode 100644 index 0000000..2e1229f Binary files /dev/null and b/Intel8080/documentation/1481550148_8080.pdf differ diff --git a/Intel8080/inc/Intel8080.h b/Intel8080/inc/Intel8080.h index c3253e3..2a7f1e4 100644 --- a/Intel8080/inc/Intel8080.h +++ b/Intel8080/inc/Intel8080.h @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -23,7 +22,7 @@ namespace EightBit { CF = Bit0, }; - Intel8080(Bus& bus, InputOutput& ports); + Intel8080(Bus& bus); Signal ExecutingInstruction; Signal ExecutedInstruction; @@ -36,14 +35,30 @@ namespace EightBit { virtual register16_t& DE() final; virtual register16_t& HL() final; + bool requestingIO() { return m_requestIO; } + bool requestingMemory() { return m_requestMemory; } + + bool requestingRead() { return raised(DBIN()); } + bool requestingWrite() { return lowered(WR()); } + + DECLARE_PIN_OUTPUT(DBIN) // Active high + DECLARE_PIN_OUTPUT(WR) // Active low + protected: - virtual void handleRESET() final; - virtual void handleINT() final; + void handleRESET() final; + void handleINT() final; + + void memoryWrite() final; + uint8_t memoryRead() final; + + void busWrite() final; + uint8_t busRead() final; private: - bool m_interruptEnable = false; + bool m_requestIO = false; + bool m_requestMemory = false; - InputOutput& m_ports; + bool m_interruptEnable = false; register16_t af; register16_t bc = Mask16; @@ -65,7 +80,7 @@ namespace EightBit { case 0b101: return L(); case 0b110: - return busRead(HL()); + return IntelProcessor::memoryRead(HL()); case 0b111: return A(); default: @@ -94,7 +109,7 @@ namespace EightBit { L() = value; break; case 0b110: - busWrite(HL(), value); + IntelProcessor::memoryWrite(HL(), value); break; case 0b111: A() = value; @@ -179,10 +194,10 @@ namespace EightBit { void xhtl(register16_t& exchange); - void writePort(uint8_t port); - void writePort(); + void portWrite(uint8_t port); + void portWrite(); - uint8_t readPort(uint8_t port); - uint8_t readPort(); + uint8_t portRead(uint8_t port); + uint8_t portRead(); }; } \ No newline at end of file diff --git a/Intel8080/src/Intel8080.cpp b/Intel8080/src/Intel8080.cpp index f6c6c66..d3465be 100644 --- a/Intel8080/src/Intel8080.cpp +++ b/Intel8080/src/Intel8080.cpp @@ -1,11 +1,13 @@ #include "stdafx.h" #include "Intel8080.h" -EightBit::Intel8080::Intel8080(Bus& bus, InputOutput& ports) -: IntelProcessor(bus), - m_ports(ports) { +EightBit::Intel8080::Intel8080(Bus& bus) +: IntelProcessor(bus){ } +DEFINE_PIN_LEVEL_CHANGERS(DBIN, Intel8080); +DEFINE_PIN_LEVEL_CHANGERS(WR, Intel8080); + EightBit::register16_t& EightBit::Intel8080::AF() { af.low = (af.low | Bit1) & ~(Bit5 | Bit3); return af; @@ -23,6 +25,31 @@ EightBit::register16_t& EightBit::Intel8080::HL() { return hl; } +void EightBit::Intel8080::memoryWrite() { + m_requestMemory = true; + IntelProcessor::memoryWrite(); + m_requestMemory = false; +} + +uint8_t EightBit::Intel8080::memoryRead() { + m_requestMemory = true; + return IntelProcessor::memoryRead(); + m_requestMemory = false; +} + +void EightBit::Intel8080::busWrite() { + lowerWR(); + IntelProcessor::busWrite(); + raiseWR(); +} + +uint8_t EightBit::Intel8080::busRead() { + raiseDBIN(); + const auto returned = IntelProcessor::busRead(); + lowerDBIN(); + return returned; +} + void EightBit::Intel8080::handleRESET() { IntelProcessor::handleRESET(); di(); @@ -236,33 +263,37 @@ void EightBit::Intel8080::cmc() { } void EightBit::Intel8080::xhtl(register16_t& exchange) { - MEMPTR().low = busRead(SP()); + MEMPTR().low = IntelProcessor::memoryRead(SP()); ++BUS().ADDRESS(); - MEMPTR().high = busRead(); - busWrite(exchange.high); + MEMPTR().high = memoryRead(); + IntelProcessor::memoryWrite(exchange.high); exchange.high = MEMPTR().high; --BUS().ADDRESS(); - busWrite(exchange.low); + IntelProcessor::memoryWrite(exchange.low); exchange.low = MEMPTR().low; } -void EightBit::Intel8080::writePort(const uint8_t port) { - BUS().ADDRESS() = register16_t(port, A()); - BUS().DATA() = A(); - writePort(); +void EightBit::Intel8080::portWrite(const uint8_t port) { + BUS().ADDRESS() = { port, port }; + portWrite(); } -void EightBit::Intel8080::writePort() { - m_ports.write(BUS().ADDRESS().low, BUS().DATA()); +void EightBit::Intel8080::portWrite() { + m_requestIO = true; + busWrite(); + m_requestIO = false; } -uint8_t EightBit::Intel8080::readPort(const uint8_t port) { - BUS().ADDRESS() = register16_t(port, A()); - return readPort(); +uint8_t EightBit::Intel8080::portRead(const uint8_t port) { + BUS().ADDRESS() = { port, port }; + return portRead(); } -uint8_t EightBit::Intel8080::readPort() { - return BUS().DATA() = m_ports.read(BUS().ADDRESS().low); +uint8_t EightBit::Intel8080::portRead() { + m_requestIO = true; + const auto returned = busRead(); + m_requestIO = false; + return returned; } int EightBit::Intel8080::step() { @@ -330,11 +361,11 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i case 0: switch (p) { case 0: // LD (BC),A - busWrite(BC(), A()); + IntelProcessor::memoryWrite(BC(), A()); tick(7); break; case 1: // LD (DE),A - busWrite(DE(), A()); + IntelProcessor::memoryWrite(DE(), A()); tick(7); break; case 2: // LD (nn),HL @@ -344,7 +375,7 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i break; case 3: // LD (nn),A BUS().ADDRESS() = fetchWord(); - busWrite(A()); + IntelProcessor::memoryWrite(A()); tick(13); break; default: @@ -354,11 +385,11 @@ 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() = busRead(BC()); + A() = IntelProcessor::memoryRead(BC()); tick(7); break; case 1: // LD A,(DE) - A() = busRead(DE()); + A() = IntelProcessor::memoryRead(DE()); tick(7); break; case 2: // LD HL,(nn) @@ -534,11 +565,11 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i tick(10); break; case 2: // OUT (n),A - writePort(fetchByte()); + portWrite(fetchByte()); tick(11); break; case 3: // IN A,(n) - A() = readPort(fetchByte()); + A() = portRead(fetchByte()); tick(11); break; case 4: // EX (SP),HL diff --git a/Intel8080/test/Board.cpp b/Intel8080/test/Board.cpp index dab1cb1..e78de3f 100644 --- a/Intel8080/test/Board.cpp +++ b/Intel8080/test/Board.cpp @@ -6,7 +6,7 @@ Board::Board(const Configuration& configuration) : m_configuration(configuration), - m_cpu(EightBit::Intel8080(*this, m_ports)), + m_cpu(EightBit::Intel8080(*this)), m_disassembler(*this) { } diff --git a/LR35902/inc/LR35902.h b/LR35902/inc/LR35902.h index 2e4f48f..78041d6 100644 --- a/LR35902/inc/LR35902.h +++ b/LR35902/inc/LR35902.h @@ -74,7 +74,7 @@ namespace EightBit { case 5: return L(); case 6: - return busRead(HL()); + return IntelProcessor::memoryRead(HL()); case 7: return A(); default: @@ -105,7 +105,7 @@ namespace EightBit { L() = value; break; case 6: - busWrite(HL(), value); + IntelProcessor::memoryWrite(HL(), value); break; case 7: A() = value; diff --git a/LR35902/src/LR35902.cpp b/LR35902/src/LR35902.cpp index b0527be..2f7ceca 100644 --- a/LR35902/src/LR35902.cpp +++ b/LR35902/src/LR35902.cpp @@ -473,19 +473,19 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in case 0: switch (p) { case 0: // LD (BC),A - busWrite(BC(), A()); + IntelProcessor::memoryWrite(BC(), A()); tick(2); break; case 1: // LD (DE),A - busWrite(DE(), A()); + IntelProcessor::memoryWrite(DE(), A()); tick(2); break; case 2: // GB: LDI (HL),A - busWrite(HL()++, A()); + IntelProcessor::memoryWrite(HL()++, A()); tick(2); break; case 3: // GB: LDD (HL),A - busWrite(HL()--, A()); + IntelProcessor::memoryWrite(HL()--, A()); tick(2); break; default: @@ -495,19 +495,19 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in case 1: switch (p) { case 0: // LD A,(BC) - A() = busRead(BC()); + A() = IntelProcessor::memoryRead(BC()); tick(2); break; case 1: // LD A,(DE) - A() = busRead(DE()); + A() = IntelProcessor::memoryRead(DE()); tick(2); break; case 2: // GB: LDI A,(HL) - A() = busRead(HL()++); + A() = IntelProcessor::memoryRead(HL()++); tick(2); break; case 3: // GB: LDD A,(HL) - A() = busRead(HL()--); + A() = IntelProcessor::memoryRead(HL()--); tick(2); break; default: @@ -642,7 +642,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in tick(2); break; case 4: // GB: LD (FF00 + n),A - busWrite(IoRegisters::BASE + fetchByte(), A()); + IntelProcessor::memoryWrite(IoRegisters::BASE + fetchByte(), A()); tick(3); break; case 5: { // GB: ADD SP,dd @@ -658,7 +658,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in tick(4); break; case 6: // GB: LD A,(FF00 + n) - A() = busRead(IoRegisters::BASE + fetchByte()); + A() = IntelProcessor::memoryRead(IoRegisters::BASE + fetchByte()); tick(3); break; case 7: { // GB: LD HL,SP + dd @@ -719,16 +719,16 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in tick(3); break; case 4: // GB: LD (FF00 + C),A - busWrite(IoRegisters::BASE + C(), A()); + IntelProcessor::memoryWrite(IoRegisters::BASE + C(), A()); tick(2); break; case 5: // GB: LD (nn),A BUS().ADDRESS() = MEMPTR() = fetchWord(); - busWrite(A()); + IntelProcessor::memoryWrite(A()); tick(4); break; case 6: // GB: LD A,(FF00 + C) - A() = busRead(IoRegisters::BASE + C()); + A() = IntelProcessor::memoryRead(IoRegisters::BASE + C()); tick(2); break; case 7: // GB: LD A,(nn) diff --git a/M6502/inc/mos6502.h b/M6502/inc/mos6502.h index 7793879..37ad510 100644 --- a/M6502/inc/mos6502.h +++ b/M6502/inc/mos6502.h @@ -140,8 +140,8 @@ namespace EightBit { void busReadModifyWrite(const uint8_t data) { // The read will have already taken place... - busWrite(); - Processor::busWrite(data); + memoryWrite(); + memoryWrite(data); } // Instruction implementations diff --git a/M6502/src/mos6502.cpp b/M6502/src/mos6502.cpp index 0dcb70b..df70158 100644 --- a/M6502/src/mos6502.cpp +++ b/M6502/src/mos6502.cpp @@ -249,30 +249,30 @@ int EightBit::MOS6502::execute() { case 0x7f: rra(AM_AbsoluteX()); break; // *RRA (absolute, X) case 0x80: AM_Immediate(); break; // *NOP (immediate) - case 0x81: Processor::busWrite(Address_IndexedIndirectX(), A()); break; // STA (indexed indirect X) + case 0x81: memoryWrite(Address_IndexedIndirectX(), A()); break; // STA (indexed indirect X) case 0x82: AM_Immediate(); break; // *NOP (immediate) - case 0x83: Processor::busWrite(Address_IndexedIndirectX(), A() & X()); break; // *SAX (indexed indirect X) - case 0x84: Processor::busWrite(Address_ZeroPage(), Y()); break; // STY (zero page) - case 0x85: Processor::busWrite(Address_ZeroPage(), A()); break; // STA (zero page) - case 0x86: Processor::busWrite(Address_ZeroPage(), X()); break; // STX (zero page) - case 0x87: Processor::busWrite(Address_ZeroPage(), A() & X()); break; // *SAX (zero page) + case 0x83: memoryWrite(Address_IndexedIndirectX(), A() & X()); break; // *SAX (indexed indirect X) + case 0x84: memoryWrite(Address_ZeroPage(), Y()); break; // STY (zero page) + case 0x85: memoryWrite(Address_ZeroPage(), A()); break; // STA (zero page) + case 0x86: memoryWrite(Address_ZeroPage(), X()); break; // STX (zero page) + case 0x87: memoryWrite(Address_ZeroPage(), A() & X()); break; // *SAX (zero page) case 0x88: busRead(); Y() = dec(Y()); break; // DEY (implied) case 0x89: AM_Immediate(); break; // *NOP (immediate) case 0x8a: busRead(); A() = through(X()); break; // TXA (implied) case 0x8b: break; - case 0x8c: Processor::busWrite(Address_Absolute(), Y()); break; // STY (absolute) - case 0x8d: Processor::busWrite(Address_Absolute(), A()); break; // STA (absolute) - case 0x8e: Processor::busWrite(Address_Absolute(), X()); break; // STX (absolute) - case 0x8f: Processor::busWrite(Address_Absolute(), A() & X()); break; // *SAX (absolute) + case 0x8c: memoryWrite(Address_Absolute(), Y()); break; // STY (absolute) + case 0x8d: memoryWrite(Address_Absolute(), A()); break; // STA (absolute) + case 0x8e: memoryWrite(Address_Absolute(), X()); break; // STX (absolute) + case 0x8f: memoryWrite(Address_Absolute(), A() & X()); break; // *SAX (absolute) case 0x90: branch(!carry()); break; // BCC (relative) - case 0x91: AM_IndirectIndexedY(); Processor::busWrite(A()); break; // STA (indirect indexed Y) + case 0x91: AM_IndirectIndexedY(); memoryWrite(A()); break; // STA (indirect indexed Y) case 0x92: break; case 0x93: break; - case 0x94: Processor::busWrite(Address_ZeroPageX(), Y()); break; // STY (zero page, X) - case 0x95: Processor::busWrite(Address_ZeroPageX(), A()); break; // STA (zero page, X) - case 0x96: Processor::busWrite(Address_ZeroPageY(), X()); break; // STX (zero page, Y) - case 0x97: Processor::busWrite(Address_ZeroPageY(), A() & X()); break; // *SAX (zero page, Y) + case 0x94: memoryWrite(Address_ZeroPageX(), Y()); break; // STY (zero page, X) + case 0x95: memoryWrite(Address_ZeroPageX(), A()); break; // STA (zero page, X) + case 0x96: memoryWrite(Address_ZeroPageY(), X()); break; // STX (zero page, Y) + case 0x97: memoryWrite(Address_ZeroPageY(), A() & X()); break; // *SAX (zero page, Y) case 0x98: busRead(); A() = through(Y()); break; // TYA (implied) case 0x99: sta_AbsoluteY(); break; // STA (absolute, Y) case 0x9a: busRead(); S() = X(); break; // TXS (implied) @@ -426,13 +426,13 @@ EightBit::register16_t EightBit::MOS6502::Address_Indirect() { uint8_t EightBit::MOS6502::Address_ZeroPageX() { const auto address = Address_ZeroPage(); - Processor::busRead(address); + memoryRead(address); return address + X(); } uint8_t EightBit::MOS6502::Address_ZeroPageY() { const auto address = Address_ZeroPage(); - Processor::busRead(address); + memoryRead(address); return address + Y(); } @@ -472,18 +472,18 @@ uint8_t EightBit::MOS6502::AM_Immediate() { } uint8_t EightBit::MOS6502::AM_Absolute() { - return Processor::busRead(Address_Absolute()); + return memoryRead(Address_Absolute()); } uint8_t EightBit::MOS6502::AM_ZeroPage() { - return Processor::busRead(Address_ZeroPage()); + return memoryRead(Address_ZeroPage()); } uint8_t EightBit::MOS6502::AM_AbsoluteX(const PageCrossingBehavior behaviour) { const auto [address, page] = Address_AbsoluteX(); auto possible = getBytePaged(page, address.low); if ((behaviour == PageCrossingBehavior::AlwaysReadTwice) || UNLIKELY(page != address.high)) - possible = Processor::busRead(address); + possible = memoryRead(address); return possible; } @@ -491,27 +491,27 @@ uint8_t EightBit::MOS6502::AM_AbsoluteY() { const auto[address, page] = Address_AbsoluteY(); auto possible = getBytePaged(page, address.low); if (UNLIKELY(page != address.high)) - possible = Processor::busRead(address); + possible = memoryRead(address); return possible; } uint8_t EightBit::MOS6502::AM_ZeroPageX() { - return Processor::busRead(Address_ZeroPageX()); + return memoryRead(Address_ZeroPageX()); } uint8_t EightBit::MOS6502::AM_ZeroPageY() { - return Processor::busRead(Address_ZeroPageY()); + return memoryRead(Address_ZeroPageY()); } uint8_t EightBit::MOS6502::AM_IndexedIndirectX() { - return Processor::busRead(Address_IndexedIndirectX()); + return memoryRead(Address_IndexedIndirectX()); } uint8_t EightBit::MOS6502::AM_IndirectIndexedY() { const auto [address, page] = Address_IndirectIndexedY(); auto possible = getBytePaged(page, address.low); if (page != address.high) - possible = Processor::busRead(address); + possible = memoryRead(address); return possible; } @@ -524,7 +524,7 @@ void EightBit::MOS6502::branch(const int condition) { const auto page = PC().high; jump(destination); if (UNLIKELY(PC().high != page)) - Processor::busRead(register16_t(PC().low, page)); + memoryRead(register16_t(PC().low, page)); } } @@ -748,11 +748,11 @@ void EightBit::MOS6502::sre(const uint8_t value) { void EightBit::MOS6502::sta_AbsoluteX() { const auto [address, page] = Address_AbsoluteX(); getBytePaged(page, address.low); - Processor::busWrite(address, A()); + memoryWrite(address, A()); } void EightBit::MOS6502::sta_AbsoluteY() { const auto [address, page] = Address_AbsoluteY(); getBytePaged(page, address.low); - Processor::busWrite(address, A()); + memoryWrite(address, A()); } diff --git a/MC6809/src/mc6809.cpp b/MC6809/src/mc6809.cpp index 5252b2c..34ce62a 100644 --- a/MC6809/src/mc6809.cpp +++ b/MC6809/src/mc6809.cpp @@ -178,18 +178,18 @@ void EightBit::mc6809::executeUnprefixed() { case 0x1c: tick(3); CC() &= AM_immediate_byte(); break; // AND (ANDCC immediate) // ASL/LSL - case 0x08: tick(6); Processor::busWrite(asl(AM_direct_byte())); break; // ASL (direct) + case 0x08: tick(6); memoryWrite(asl(AM_direct_byte())); break; // ASL (direct) case 0x48: tick(2); A() = asl(A()); break; // ASL (ASLA inherent) case 0x58: tick(2); B() = asl(B()); break; // ASL (ASLB inherent) - case 0x68: tick(6); Processor::busWrite(asl(AM_indexed_byte())); break; // ASL (indexed) - case 0x78: tick(7); Processor::busWrite(asl(AM_extended_byte())); break; // ASL (extended) + case 0x68: tick(6); memoryWrite(asl(AM_indexed_byte())); break; // ASL (indexed) + case 0x78: tick(7); memoryWrite(asl(AM_extended_byte())); break; // ASL (extended) // ASR - case 0x07: tick(6); Processor::busWrite(asr(AM_direct_byte())); break; // ASR (direct) + case 0x07: tick(6); memoryWrite(asr(AM_direct_byte())); break; // ASR (direct) case 0x47: tick(2); A() = asr(A()); break; // ASR (ASRA inherent) case 0x57: tick(2); B() = asr(B()); break; // ASR (ASRB inherent) - case 0x67: tick(6); Processor::busWrite(asr(AM_indexed_byte())); break; // ASR (indexed) - case 0x77: tick(7); Processor::busWrite(asr(AM_extended_byte())); break; // ASR (extended) + case 0x67: tick(6); memoryWrite(asr(AM_indexed_byte())); break; // ASR (indexed) + case 0x77: tick(7); memoryWrite(asr(AM_extended_byte())); break; // ASR (extended) // BIT case 0x85: tick(2); bit(A(), AM_immediate_byte()); break; // BIT (BITA immediate) @@ -203,11 +203,11 @@ void EightBit::mc6809::executeUnprefixed() { case 0xf5: tick(5); bit(B(), AM_extended_byte()); break; // BIT (BITB extended) // CLR - case 0x0f: tick(6); Processor::busWrite(Address_direct(), clr()); break; // CLR (direct) + case 0x0f: tick(6); memoryWrite(Address_direct(), clr()); break; // CLR (direct) case 0x4f: tick(2); A() = clr(); break; // CLR (CLRA implied) case 0x5f: tick(2); B() = clr(); break; // CLR (CLRB implied) - case 0x6f: tick(6); Processor::busWrite(Address_indexed(), clr()); break; // CLR (indexed) - case 0x7f: tick(7); Processor::busWrite(Address_extended(), clr()); break; // CLR (extended) + case 0x6f: tick(6); memoryWrite(Address_indexed(), clr()); break; // CLR (indexed) + case 0x7f: tick(7); memoryWrite(Address_extended(), clr()); break; // CLR (extended) // CMP @@ -230,11 +230,11 @@ void EightBit::mc6809::executeUnprefixed() { case 0xbc: tick(7); cmp(X(), AM_extended_word()); break; // CMP (CMPX, extended) // COM - case 0x03: tick(6); Processor::busWrite(com(AM_direct_byte())); break; // COM (direct) + case 0x03: tick(6); memoryWrite(com(AM_direct_byte())); break; // COM (direct) case 0x43: tick(2); A() = com(A()); break; // COM (COMA inherent) case 0x53: tick(2); B() = com(B()); break; // COM (COMB inherent) - case 0x63: tick(6); Processor::busWrite(com(AM_indexed_byte())); break; // COM (indexed) - case 0x73: tick(7); Processor::busWrite(com(AM_extended_byte())); break; // COM (extended) + case 0x63: tick(6); memoryWrite(com(AM_indexed_byte())); break; // COM (indexed) + case 0x73: tick(7); memoryWrite(com(AM_extended_byte())); break; // COM (extended) // CWAI case 0x3c: tick(11); cwai(AM_direct_byte()); break; // CWAI (direct) @@ -243,11 +243,11 @@ void EightBit::mc6809::executeUnprefixed() { case 0x19: tick(2); A() = da(A()); break; // DAA (inherent) // DEC - case 0x0a: tick(6); Processor::busWrite(dec(AM_direct_byte())); break; // DEC (direct) + case 0x0a: tick(6); memoryWrite(dec(AM_direct_byte())); break; // DEC (direct) case 0x4a: tick(2); A() = dec(A()); break; // DEC (DECA inherent) case 0x5a: tick(2); B() = dec(B()); break; // DEC (DECB inherent) - case 0x6a: tick(6); Processor::busWrite(dec(AM_indexed_byte())); break; // DEC (indexed) - case 0x7a: tick(7); Processor::busWrite(dec(AM_extended_byte())); break; // DEC (extended) + case 0x6a: tick(6); memoryWrite(dec(AM_indexed_byte())); break; // DEC (indexed) + case 0x7a: tick(7); memoryWrite(dec(AM_extended_byte())); break; // DEC (extended) // EOR @@ -267,11 +267,11 @@ void EightBit::mc6809::executeUnprefixed() { case 0x1e: tick(8); exg(AM_immediate_byte()); break; // EXG (R1,R2 immediate) // INC - case 0x0c: tick(6); Processor::busWrite(inc(AM_direct_byte())); break; // INC (direct) + case 0x0c: tick(6); memoryWrite(inc(AM_direct_byte())); break; // INC (direct) case 0x4c: tick(2); A() = inc(A()); break; // INC (INCA inherent) case 0x5c: tick(2); B() = inc(B()); break; // INC (INCB inherent) - case 0x6c: tick(6); Processor::busWrite(inc(AM_indexed_byte())); break; // INC (indexed) - case 0x7c: tick(7); Processor::busWrite(inc(AM_extended_byte())); break; // INC (extended) + case 0x6c: tick(6); memoryWrite(inc(AM_indexed_byte())); break; // INC (indexed) + case 0x7c: tick(7); memoryWrite(inc(AM_extended_byte())); break; // INC (extended) // JMP case 0x0e: tick(6); jump(Address_direct()); break; // JMP (direct) @@ -322,21 +322,21 @@ void EightBit::mc6809::executeUnprefixed() { case 0x33: tick(4); U() = Address_indexed(); break; // LEA (LEAU indexed) // LSR - case 0x04: tick(6); Processor::busWrite(lsr(AM_direct_byte())); break; // LSR (direct) + case 0x04: tick(6); memoryWrite(lsr(AM_direct_byte())); break; // LSR (direct) case 0x44: tick(2); A() = lsr(A()); break; // LSR (LSRA inherent) case 0x54: tick(2); B() = lsr(B()); break; // LSR (LSRB inherent) - case 0x64: tick(6); Processor::busWrite(lsr(AM_indexed_byte())); break; // LSR (indexed) - case 0x74: tick(7); Processor::busWrite(lsr(AM_extended_byte())); break; // LSR (extended) + case 0x64: tick(6); memoryWrite(lsr(AM_indexed_byte())); break; // LSR (indexed) + case 0x74: tick(7); memoryWrite(lsr(AM_extended_byte())); break; // LSR (extended) // MUL case 0x3d: tick(11); D() = mul(A(), B()); break; // MUL (inherent) // NEG - case 0x00: tick(6); Processor::busWrite(neg(AM_direct_byte())); break; // NEG (direct) + case 0x00: tick(6); memoryWrite(neg(AM_direct_byte())); break; // NEG (direct) case 0x40: tick(2); A() = neg(A()); break; // NEG (NEGA, inherent) case 0x50: tick(2); B() = neg(B()); break; // NEG (NEGB, inherent) - case 0x60: tick(6); Processor::busWrite(neg(AM_indexed_byte())); break; // NEG (indexed) - case 0x70: tick(7); Processor::busWrite(neg(AM_extended_byte())); break; // NEG (extended) + case 0x60: tick(6); memoryWrite(neg(AM_indexed_byte())); break; // NEG (indexed) + case 0x70: tick(7); memoryWrite(neg(AM_extended_byte())); break; // NEG (extended) // NOP case 0x12: tick(2); break; // NOP (inherent) @@ -367,18 +367,18 @@ void EightBit::mc6809::executeUnprefixed() { case 0x37: tick(5); pul(U(), AM_immediate_byte()); break; // PUL (PULU immediate) // ROL - case 0x09: tick(6); Processor::busWrite(rol(AM_direct_byte())); break; // ROL (direct) + case 0x09: tick(6); memoryWrite(rol(AM_direct_byte())); break; // ROL (direct) case 0x49: tick(2); A() = rol(A()); break; // ROL (ROLA inherent) case 0x59: tick(2); B() = rol(B()); break; // ROL (ROLB inherent) - case 0x69: tick(6); Processor::busWrite(rol(AM_indexed_byte())); break; // ROL (indexed) - case 0x79: tick(7); Processor::busWrite(rol(AM_extended_byte())); break; // ROL (extended) + case 0x69: tick(6); memoryWrite(rol(AM_indexed_byte())); break; // ROL (indexed) + case 0x79: tick(7); memoryWrite(rol(AM_extended_byte())); break; // ROL (extended) // ROR - case 0x06: tick(6); Processor::busWrite(ror(AM_direct_byte())); break; // ROR (direct) + case 0x06: tick(6); memoryWrite(ror(AM_direct_byte())); break; // ROR (direct) case 0x46: tick(2); A() = ror(A()); break; // ROR (RORA inherent) case 0x56: tick(2); B() = ror(B()); break; // ROR (RORB inherent) - case 0x66: tick(6); Processor::busWrite(ror(AM_indexed_byte())); break; // ROR (indexed) - case 0x76: tick(7); Processor::busWrite(ror(AM_extended_byte())); break; // ROR (extended) + case 0x66: tick(6); memoryWrite(ror(AM_indexed_byte())); break; // ROR (indexed) + case 0x76: tick(7); memoryWrite(ror(AM_extended_byte())); break; // ROR (extended) // RTI case 0x3B: tick(6); rti(); break; // RTI (inherent) @@ -406,14 +406,14 @@ void EightBit::mc6809::executeUnprefixed() { // ST // STA - case 0x97: tick(4); Processor::busWrite(Address_direct(), st(A())); break; // ST (STA direct) - case 0xa7: tick(4); Processor::busWrite(Address_indexed(), st(A())); break; // ST (STA indexed) - case 0xb7: tick(5); Processor::busWrite(Address_extended(), st(A())); break; // ST (STA extended) + case 0x97: tick(4); memoryWrite(Address_direct(), st(A())); break; // ST (STA direct) + case 0xa7: tick(4); memoryWrite(Address_indexed(), st(A())); break; // ST (STA indexed) + case 0xb7: tick(5); memoryWrite(Address_extended(), st(A())); break; // ST (STA extended) // STB - case 0xd7: tick(4); Processor::busWrite(Address_direct(), st(B())); break; // ST (STB direct) - case 0xe7: tick(4); Processor::busWrite(Address_indexed(), st(B())); break; // ST (STB indexed) - case 0xf7: tick(5); Processor::busWrite(Address_extended(), st(B())); break; // ST (STB extended) + case 0xd7: tick(4); memoryWrite(Address_direct(), st(B())); break; // ST (STB direct) + case 0xe7: tick(4); memoryWrite(Address_indexed(), st(B())); break; // ST (STB indexed) + case 0xf7: tick(5); memoryWrite(Address_extended(), st(B())); break; // ST (STB extended) // STD case 0xdd: tick(5); Processor::setWord(Address_direct(), st(D())); break; // ST (STD direct) @@ -605,11 +605,11 @@ uint8_t EightBit::mc6809::pop() { } void EightBit::mc6809::push(register16_t& stack, const uint8_t value) { - Processor::busWrite(--stack, value); + memoryWrite(--stack, value); } uint8_t EightBit::mc6809::pop(register16_t& stack) { - return Processor::busRead(stack++); + return memoryRead(stack++); } // @@ -733,15 +733,15 @@ uint8_t EightBit::mc6809::AM_immediate_byte() { } uint8_t EightBit::mc6809::AM_direct_byte() { - return Processor::busRead(Address_direct()); + return memoryRead(Address_direct()); } uint8_t EightBit::mc6809::AM_indexed_byte() { - return Processor::busRead(Address_indexed()); + return memoryRead(Address_indexed()); } uint8_t EightBit::mc6809::AM_extended_byte() { - return Processor::busRead(Address_extended()); + return memoryRead(Address_extended()); } // diff --git a/Z80/fusetest_Z80/FuseTestRunner.cpp b/Z80/fusetest_Z80/FuseTestRunner.cpp index 16d8783..f15f39a 100644 --- a/Z80/fusetest_Z80/FuseTestRunner.cpp +++ b/Z80/fusetest_Z80/FuseTestRunner.cpp @@ -2,12 +2,13 @@ #include "FuseTestRunner.h" #include "Disassembler.h" +#include #include Fuse::TestRunner::TestRunner(const Test& test, const ExpectedTestResult& result) : m_test(test), m_result(result), - m_cpu(*this, m_ports), + m_cpu(*this), m_totalCycles(0) { for (const auto& event : m_result.events.events) { @@ -20,20 +21,27 @@ Fuse::TestRunner::TestRunner(const Test& test, const ExpectedTestResult& result) }); ReadByte.connect([this](EightBit::EventArgs&) { - addActualEvent("MR"); + addActualEvent(currentBusAccessType() + "R"); }); WrittenByte.connect([this](EightBit::EventArgs&) { - addActualEvent("MW"); + addActualEvent(currentBusAccessType() + "W"); }); +} - m_ports.ReadPort.connect([this](uint8_t port) { - addActualEvent("PR"); - }); +std::string Fuse::TestRunner::currentBusAccessType() { - m_ports.WrittenPort.connect([this](uint8_t port) { - addActualEvent("PW"); - }); + const bool ioRequest = m_cpu.requestingIO(); + const bool memoryRequest = m_cpu.requestingMemory(); + if (ioRequest && memoryRequest) + throw std::logic_error("Invalid bus state (both IORQ and MREQ lowered"); + + if (ioRequest) + return "P"; + if (memoryRequest) + return "M"; + + throw std::logic_error("Invalid bus state (neither IORQ and MREQ lowered"); } void Fuse::TestRunner::addActualEvent(const std::string& specifier) { @@ -62,6 +70,39 @@ void Fuse::TestRunner::lowerPOWER() { EightBit::Bus::lowerPOWER(); } +EightBit::MemoryMapping Fuse::TestRunner::mapping(uint16_t address) { + + const bool memory = m_cpu.requestingMemory(); + if (memory) + return { + m_ram, + 0x0000, + 0xffff, + EightBit::MemoryMapping::AccessLevel::ReadWrite + }; + + const bool io = m_cpu.requestingIO(); + if (io) { + + m_ports.setAccessType(EightBit::InputOutput::AccessType::Unknown); + + const bool reading = m_cpu.requestingRead(); + if (reading) + m_ports.setAccessType(EightBit::InputOutput::AccessType::Reading); + + const bool writing = m_cpu.requestingWrite(); + if (writing) + m_ports.setAccessType(EightBit::InputOutput::AccessType::Writing); + + return { + m_ports, + 0x0000, + 0xff, + EightBit::MemoryMapping::AccessLevel::ReadWrite + }; + } +} + void Fuse::TestRunner::initialise() { initialiseMemory(); } @@ -102,7 +143,7 @@ void Fuse::TestRunner::initialiseMemory() { auto address = memoryDatum.address; auto bytes = memoryDatum.bytes; for (int i = 0; i < bytes.size(); ++i) - poke(address + i, bytes[i]); + m_ram.poke(address + i, bytes[i]); } } @@ -350,7 +391,7 @@ void Fuse::TestRunner::checkMemory() { for (int i = 0; i < bytes.size(); ++i) { auto expected = bytes[i]; uint16_t address = memoryDatum.address + i; - auto actual = peek(address); + auto actual = m_ram.peek(address); if (expected != actual) { m_failed = true; if (first) { diff --git a/Z80/fusetest_Z80/FuseTestRunner.h b/Z80/fusetest_Z80/FuseTestRunner.h index 34511a5..2dbdb53 100644 --- a/Z80/fusetest_Z80/FuseTestRunner.h +++ b/Z80/fusetest_Z80/FuseTestRunner.h @@ -40,6 +40,7 @@ namespace Fuse { const std::string& lowDescription, EightBit::register16_t actual, EightBit::register16_t expected) const; + std::string currentBusAccessType(); void addActualEvent(const std::string& specifier); void dumpExpectedEvents() const; void dumpActualEvents() const; @@ -48,9 +49,7 @@ namespace Fuse { static void dumpEvent(const TestEvent& event); protected: - virtual EightBit::MemoryMapping mapping(uint16_t address) final { - return { m_ram, 0x0000, 0xffff, EightBit::MemoryMapping::AccessLevel::ReadWrite }; - } + virtual EightBit::MemoryMapping mapping(uint16_t address) final; public: TestRunner(const Test& test, const ExpectedTestResult& expected); diff --git a/Z80/inc/Z80.h b/Z80/inc/Z80.h index 216aefe..39d4dee 100644 --- a/Z80/inc/Z80.h +++ b/Z80/inc/Z80.h @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -47,12 +46,11 @@ namespace EightBit { CF = Bit0, }; - Z80(Bus& bus, InputOutput& ports); + Z80(Bus& bus); Signal ExecutingInstruction; Signal ExecutedInstruction; - int execute(uint8_t opcode) { return IntelProcessor::execute(opcode); } int execute() final; int step() final; @@ -95,6 +93,12 @@ namespace EightBit { m_accumulatorFlagsSet ^= 1; } + bool requestingIO() { return lowered(IORQ()); } + bool requestingMemory() { return lowered(MREQ()); } + + bool requestingRead() { return lowered(RD()); } + bool requestingWrite() { return lowered(WR()); } + DECLARE_PIN_INPUT(NMI) DECLARE_PIN_OUTPUT(M1) @@ -118,12 +122,13 @@ namespace EightBit { IntelProcessor::pushWord(destination); } + void memoryWrite() final; + uint8_t memoryRead() final; + void busWrite() final; uint8_t busRead() final; private: - InputOutput& m_ports; - enum { BC_IDX, DE_IDX, HL_IDX }; std::array, 2> m_registers; @@ -176,10 +181,9 @@ namespace EightBit { uint8_t readInitialOpCode() { tick(); lowerM1(); - const auto returned = IntelProcessor::busRead(PC()); + const auto returned = IntelProcessor::memoryRead(PC()); raiseM1(); - BUS().ADDRESS().low = REFRESH(); - BUS().ADDRESS().high = IV(); + BUS().ADDRESS() = { REFRESH(), IV() }; lowerRFSH(); lowerMREQ(); raiseMREQ(); @@ -253,7 +257,7 @@ namespace EightBit { case 5: return HL2().low; case 6: - return IntelProcessor::busRead(UNLIKELY(m_displaced) ? displacedAddress() : HL().word); + return IntelProcessor::memoryRead(UNLIKELY(m_displaced) ? displacedAddress() : HL().word); case 7: return A(); default: @@ -284,7 +288,7 @@ namespace EightBit { HL2().low = value; break; case 6: - IntelProcessor::busWrite(UNLIKELY(m_displaced) ? displacedAddress() : HL().word, value); + IntelProcessor::memoryWrite(UNLIKELY(m_displaced) ? displacedAddress() : HL().word, value); break; case 7: A() = value; @@ -317,7 +321,7 @@ namespace EightBit { L() = value; break; case 6: - IntelProcessor::busWrite(HL(), value); + IntelProcessor::memoryWrite(HL(), value); break; case 7: A() = value; @@ -446,10 +450,10 @@ namespace EightBit { void rrd(uint8_t& f, register16_t address, uint8_t& update); void rld(uint8_t& f, register16_t address, uint8_t& update); - void writePort(uint8_t port); - void writePort(); + void portWrite(uint8_t port); + void portWrite(); - uint8_t readPort(uint8_t port); - uint8_t readPort(); + uint8_t portRead(uint8_t port); + uint8_t portRead(); }; } \ No newline at end of file diff --git a/Z80/src/Z80.cpp b/Z80/src/Z80.cpp index 60365cd..19551ab 100644 --- a/Z80/src/Z80.cpp +++ b/Z80/src/Z80.cpp @@ -3,9 +3,8 @@ // based on http://www.z80.info/decoding.htm -EightBit::Z80::Z80(Bus& bus, InputOutput& ports) -: IntelProcessor(bus), - m_ports(ports) { +EightBit::Z80::Z80(Bus& bus) +: IntelProcessor(bus) { RaisedPOWER.connect([this](EventArgs) { raiseM1(); @@ -58,22 +57,33 @@ EightBit::register16_t& EightBit::Z80::HL() { return m_registers[m_registerSet][HL_IDX]; } -void EightBit::Z80::busWrite() { - tick(3); +void EightBit::Z80::memoryWrite() { + tick(2); lowerMREQ(); - lowerWR(); - IntelProcessor::busWrite(); - raiseWR(); + IntelProcessor::memoryWrite(); raiseMREQ(); } -uint8_t EightBit::Z80::busRead() { - tick(3); +uint8_t EightBit::Z80::memoryRead() { + tick(2); lowerMREQ(); + const auto returned = IntelProcessor::memoryRead(); + raiseMREQ(); + return returned; +} + +void EightBit::Z80::busWrite() { + tick(); + lowerWR(); + IntelProcessor::busWrite(); + raiseWR(); +} + +uint8_t EightBit::Z80::busRead() { + tick(); lowerRD(); const auto returned = IntelProcessor::busRead(); raiseRD(); - raiseMREQ(); return returned; } @@ -107,7 +117,7 @@ void EightBit::Z80::handleINT() { tick(5); switch (IM()) { case 0: // i8080 equivalent - execute(data); + IntelProcessor::execute(data); break; case 1: tick(); @@ -481,20 +491,20 @@ void EightBit::Z80::ccf(uint8_t& f, const uint8_t operand) { } void EightBit::Z80::xhtl(register16_t& exchange) { - MEMPTR().low = IntelProcessor::busRead(SP()); + MEMPTR().low = IntelProcessor::memoryRead(SP()); ++BUS().ADDRESS(); - MEMPTR().high = busRead(); + MEMPTR().high = memoryRead(); tick(); - IntelProcessor::busWrite(exchange.high); + IntelProcessor::memoryWrite(exchange.high); exchange.high = MEMPTR().high; --BUS().ADDRESS(); - IntelProcessor::busWrite(exchange.low); + IntelProcessor::memoryWrite(exchange.low); exchange.low = MEMPTR().low; } void EightBit::Z80::blockCompare(uint8_t& f, const uint8_t value, const register16_t source, register16_t& counter) { - const auto contents = IntelProcessor::busRead(source); + const auto contents = IntelProcessor::memoryRead(source); uint8_t result = value - contents; f = setBit(f, PF, --counter.word); @@ -530,8 +540,8 @@ bool EightBit::Z80::cpdr(uint8_t& f, uint8_t value) { } void EightBit::Z80::blockLoad(uint8_t& f, const uint8_t a, const register16_t source, const register16_t destination, register16_t& counter) { - const auto value = IntelProcessor::busRead(source); - IntelProcessor::busWrite(destination, value); + const auto value = IntelProcessor::memoryRead(source); + IntelProcessor::memoryWrite(destination, value); const auto xy = a + value; f = setBit(f, XF, xy & Bit3); f = setBit(f, YF, xy & Bit1); @@ -560,9 +570,9 @@ bool EightBit::Z80::lddr(uint8_t& f, const uint8_t a) { void EightBit::Z80::blockIn(register16_t& source, const register16_t destination) { MEMPTR() = BUS().ADDRESS() = source; tick(); - const auto value = readPort(); + const auto value = portRead(); tick(3); - IntelProcessor::busWrite(destination, value); + IntelProcessor::memoryWrite(destination, value); source.high = decrement(F(), source.high); F() = setBit(F(), NF); } @@ -589,10 +599,10 @@ bool EightBit::Z80::indr() { void EightBit::Z80::blockOut(const register16_t source, register16_t& destination) { tick(); - const auto value = IntelProcessor::busRead(source); + const auto value = IntelProcessor::memoryRead(source); destination.high = decrement(F(), destination.high); BUS().ADDRESS() = destination; - writePort(); + portWrite(); MEMPTR() = destination; F() = setBit(F(), NF, value & Bit7); F() = setBit(F(), HC | CF, (L() + value) > 0xff); @@ -621,9 +631,9 @@ bool EightBit::Z80::otdr() { void EightBit::Z80::rrd(uint8_t& f, register16_t address, uint8_t& update) { (MEMPTR() = BUS().ADDRESS() = address)++; - const auto memory = busRead(); + const auto memory = memoryRead(); tick(4); - IntelProcessor::busWrite(promoteNibble(update) | highNibble(memory)); + IntelProcessor::memoryWrite(promoteNibble(update) | highNibble(memory)); update = higherNibble(update) | lowerNibble(memory); f = adjustSZPXY(f, update); f = clearBit(f, NF | HC); @@ -631,42 +641,36 @@ void EightBit::Z80::rrd(uint8_t& f, register16_t address, uint8_t& update) { void EightBit::Z80::rld(uint8_t& f, register16_t address, uint8_t& update) { (MEMPTR() = BUS().ADDRESS() = address)++; - const auto memory = busRead(); + const auto memory = memoryRead(); tick(4); - IntelProcessor::busWrite(promoteNibble(memory) | lowNibble(update)); + IntelProcessor::memoryWrite(promoteNibble(memory) | lowNibble(update)); update = higherNibble(update) | highNibble(memory); f = adjustSZPXY(f, update); f = clearBit(f, NF | HC); } -void EightBit::Z80::writePort(const uint8_t port) { +void EightBit::Z80::portWrite(const uint8_t port) { MEMPTR() = BUS().ADDRESS() = { port, A() }; BUS().DATA() = A(); - writePort(); + portWrite(); ++MEMPTR().low; } -void EightBit::Z80::writePort() { - tick(); +void EightBit::Z80::portWrite() { lowerIORQ(); - lowerWR(); - m_ports.write(BUS().ADDRESS().low, BUS().DATA()); - raiseWR(); + busWrite(); raiseIORQ(); } -uint8_t EightBit::Z80::readPort(const uint8_t port) { +uint8_t EightBit::Z80::portRead(const uint8_t port) { MEMPTR() = BUS().ADDRESS() = { port, A() }; ++MEMPTR().low; - return readPort(); + return portRead(); } -uint8_t EightBit::Z80::readPort() { - tick(); +uint8_t EightBit::Z80::portRead() { lowerIORQ(); - lowerRD(); - const auto returned = BUS().DATA() = m_ports.read(BUS().ADDRESS().low); - raiseRD(); + const auto returned = busRead(); raiseIORQ(); return returned; } @@ -706,11 +710,11 @@ int EightBit::Z80::step() { // CPU.The HALT acknowledge signal is active during this time indicating that the processor // is in the HALT state. const auto discarded = readInitialOpCode(); - execute(0); // NOP + IntelProcessor::execute(0); // NOP handled = true; } if (!handled) - execute(fetchInitialOpCode()); + IntelProcessor::execute(fetchInitialOpCode()); } ExecutedInstruction.fire(*this); return cycles(); @@ -747,7 +751,7 @@ void EightBit::Z80::executeCB(const int x, const int y, const int z) { uint8_t operand; if (m_displaced) { tick(2); - operand = IntelProcessor::busRead(displacedAddress()); + operand = IntelProcessor::memoryRead(displacedAddress()); } else { operand = R(z); } @@ -801,7 +805,7 @@ void EightBit::Z80::executeCB(const int x, const int y, const int z) { if (update) { tick(); if (m_displaced) { - IntelProcessor::busWrite(operand); + IntelProcessor::memoryWrite(operand); if (!memoryZ) R2(z, operand); } else { @@ -820,7 +824,7 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p switch (z) { case 0: // Input from port with 16-bit address (MEMPTR() = BUS().ADDRESS() = BC())++; - readPort(); + portRead(); if (y != 6) // IN r[y],(C) R(y, BUS().DATA()); F() = adjustSZPXY(F(), BUS().DATA()); @@ -829,7 +833,7 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p case 1: // Output to port with 16-bit address (MEMPTR() = BUS().ADDRESS() = BC())++; BUS().DATA() = y == 6 ? 0 : R(y); - writePort(); + portWrite(); break; case 2: // 16-bit add/subtract with carry switch (q) { @@ -1080,12 +1084,12 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in case 0: // LD (BC),A (MEMPTR() = BUS().ADDRESS() = BC())++; MEMPTR().high = BUS().DATA() = A(); - busWrite(); + memoryWrite(); break; case 1: // LD (DE),A (MEMPTR() = BUS().ADDRESS() = DE())++; MEMPTR().high = BUS().DATA() = A(); - busWrite(); + memoryWrite(); break; case 2: // LD (nn),HL BUS().ADDRESS() = fetchWord(); @@ -1094,7 +1098,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in case 3: // LD (nn),A (MEMPTR() = BUS().ADDRESS() = fetchWord())++; MEMPTR().high = BUS().DATA() = A(); - busWrite(); + memoryWrite(); break; default: UNREACHABLE; @@ -1104,11 +1108,11 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in switch (p) { case 0: // LD A,(BC) (MEMPTR() = BUS().ADDRESS() = BC())++; - A() = busRead(); + A() = memoryRead(); break; case 1: // LD A,(DE) (MEMPTR() = BUS().ADDRESS() = DE())++; - A() = busRead(); + A() = memoryRead(); break; case 2: // LD HL,(nn) BUS().ADDRESS() = fetchWord(); @@ -1116,7 +1120,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in break; case 3: // LD A,(nn) (MEMPTR() = BUS().ADDRESS() = fetchWord())++; - A() = busRead(); + A() = memoryRead(); break; default: UNREACHABLE; @@ -1329,16 +1333,16 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in m_prefixCB = true; if (m_displaced) { fetchDisplacement(); - execute(fetchByte()); + IntelProcessor::execute(fetchByte()); } else { - execute(fetchInitialOpCode()); + IntelProcessor::execute(fetchInitialOpCode()); } break; case 2: // OUT (n),A - writePort(fetchByte()); + portWrite(fetchByte()); break; case 3: // IN A,(n) - A() = readPort(fetchByte()); + A() = portRead(fetchByte()); break; case 4: // EX (SP),HL xhtl(HL2()); @@ -1371,15 +1375,15 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in break; case 1: // DD prefix m_displaced = m_prefixDD = true; - execute(fetchInitialOpCode()); + IntelProcessor::execute(fetchInitialOpCode()); break; case 2: // ED prefix m_prefixED = true; - execute(fetchInitialOpCode()); + IntelProcessor::execute(fetchInitialOpCode()); break; case 3: // FD prefix m_displaced = m_prefixFD = true; - execute(fetchInitialOpCode()); + IntelProcessor::execute(fetchInitialOpCode()); break; default: UNREACHABLE; diff --git a/Z80/test/Board.h b/Z80/test/Board.h index 27d2c4e..6cf9d13 100644 --- a/Z80/test/Board.h +++ b/Z80/test/Board.h @@ -32,7 +32,7 @@ private: const Configuration& m_configuration; EightBit::Ram m_ram = 0x10000; EightBit::InputOutput m_ports; - EightBit::Z80 m_cpu = { *this, m_ports }; + EightBit::Z80 m_cpu = *this; EightBit::Disassembler m_disassembler = *this; EightBit::Profiler m_profiler = { m_cpu, m_disassembler }; int m_warmstartCount = 0; diff --git a/inc/Bus.h b/inc/Bus.h index 6821cc7..c67e75c 100644 --- a/inc/Bus.h +++ b/inc/Bus.h @@ -27,11 +27,11 @@ namespace EightBit { [[nodiscard]] auto& DATA() noexcept { return m_data; } [[nodiscard]] auto peek() { return reference(); } - [[nodiscard]] auto peek(const uint16_t address) { return reference(address); } - [[nodiscard]] auto peek(const register16_t address) { return reference(address.word); } + [[nodiscard]] virtual uint8_t peek(const uint16_t address) { return reference(address); } + [[nodiscard]] auto peek(const register16_t address) { return peek(address.word); } void poke(const uint8_t value) { reference() = value; } - void poke(const uint16_t address, const uint8_t value) { reference(address) = value; } - void poke(const register16_t address, const uint8_t value) { reference(address.word) = value; } + virtual void poke(const uint16_t address, const uint8_t value) { reference(address) = value; } + void poke(const register16_t address, const uint8_t value) { poke(address.word, value); } [[nodiscard]] uint8_t read(); template [[nodiscard]] auto read(const T address) { diff --git a/inc/InputOutput.h b/inc/InputOutput.h index 0b6e51e..eb2954f 100644 --- a/inc/InputOutput.h +++ b/inc/InputOutput.h @@ -4,36 +4,51 @@ #include #include "Signal.h" +#include "Memory.h" +#include "Ram.h" namespace EightBit { - class InputOutput final { + class InputOutput final : public Memory { public: + enum class AccessType { Unknown, Reading, Writing }; + InputOutput() = default; - [[nodiscard]] auto read(const uint8_t port) { return readInputPort(port); } - void write(const uint8_t port, const uint8_t value) { writeOutputPort(port, value); } + [[nodiscard]] size_t size() const override; + [[nodiscard]] uint8_t peek(uint16_t address) const override; - [[nodiscard]] uint8_t readInputPort(uint8_t port); - void writeInputPort(const uint8_t port, const uint8_t value) noexcept { m_input[port] = value; } + [[nodiscard]] uint8_t& reference(uint16_t address) override; - [[nodiscard]] auto readOutputPort(const uint8_t port) noexcept { return m_output[port]; } - void writeOutputPort(uint8_t port, uint8_t value); + int load(std::ifstream& file, int writeOffset = 0, int readOffset = 0, int limit = -1) override; + int load(const std::string& path, int writeOffset = 0, int readOffset = 0, int limit = -1) override; + int load(const std::vector& bytes, int writeOffset = 0, int readOffset = 0, int limit = -1) override; - Signal ReadingPort; - Signal ReadPort; + AccessType getAccessType() const noexcept { return m_access; } + void setAccessType(AccessType value) noexcept { m_access = value; } - Signal WritingPort; - Signal WrittenPort; + auto readPort(uint8_t port, AccessType access) { + setAccessType(access); + return reference(port); + } + + auto readInputPort(uint8_t port) { return readPort(port, AccessType::Reading); } + auto readOutputPort(uint8_t port) { return readPort(port, AccessType::Writing); } + + void writePort(uint8_t port, uint8_t value, AccessType access) { + setAccessType(access); + reference(port) = value; + } + + auto writeInputPort(uint8_t port, uint8_t value) { return writePort(port, value, AccessType::Reading); } + auto writeOutputPort(uint8_t port, uint8_t value) { return writePort(port, value, AccessType::Writing); } protected: - void OnReadingPort(uint8_t port); - void OnReadPort(uint8_t port); - - void OnWritingPort(uint8_t port); - void OnWrittenPort(uint8_t port); + void poke(uint16_t address, uint8_t value) override; private: - std::array m_input = { 0 }; - std::array m_output = { 0 }; + Ram m_input = 0x100; + Ram m_output = 0x100; + + AccessType m_access = AccessType::Unknown; }; } diff --git a/inc/IntelProcessor.h b/inc/IntelProcessor.h index be39d7b..990a998 100644 --- a/inc/IntelProcessor.h +++ b/inc/IntelProcessor.h @@ -161,7 +161,7 @@ namespace EightBit { auto jrConditional(const int condition) { const auto offsetAddress = PC()++; if (condition) { - const auto offset = busRead(offsetAddress); + const auto offset = memoryRead(offsetAddress); jr(offset); } return condition; diff --git a/inc/Memory.h b/inc/Memory.h index fb29cf5..e7c458e 100644 --- a/inc/Memory.h +++ b/inc/Memory.h @@ -8,7 +8,7 @@ namespace EightBit { // Memory is: // *) Definitely has a size - // *) Definitely 'peek'able (although you might not like the answer you get!) + // *) Probably 'peek'able (although you might not like the answer you get!) // *) Probably 'load'able (i.e. able to be externally initialised) // *) At the implementation level, probably 'poke'able (although may not be exposed to users) // *) Possibly 'reference'able (Very likely if you've exposed 'poke') diff --git a/inc/Processor.h b/inc/Processor.h index 4303e8a..7d2aa02 100644 --- a/inc/Processor.h +++ b/inc/Processor.h @@ -41,23 +41,25 @@ namespace EightBit { virtual void handleRESET(); virtual void handleINT(); - void busWrite(register16_t address, uint8_t data); - void busWrite(uint8_t data); + void memoryWrite(register16_t address, uint8_t data); + void memoryWrite(uint8_t data); + virtual void memoryWrite(); virtual void busWrite(); - uint8_t busRead(register16_t address); + uint8_t memoryRead(register16_t address); + virtual uint8_t memoryRead(); virtual uint8_t busRead(); auto getBytePaged(const uint8_t page, const uint8_t offset) { - return busRead(register16_t(offset, page)); + return memoryRead(register16_t(offset, page)); } void setBytePaged(const uint8_t page, const uint8_t offset, const uint8_t value) { - busWrite(register16_t(offset, page), value); + memoryWrite(register16_t(offset, page), value); } auto fetchByte() { - return busRead(PC()++); + return memoryRead(PC()++); } [[nodiscard]] virtual register16_t getWord() = 0; diff --git a/src/BigEndianProcessor.cpp b/src/BigEndianProcessor.cpp index b972b89..527bdb9 100644 --- a/src/BigEndianProcessor.cpp +++ b/src/BigEndianProcessor.cpp @@ -5,29 +5,29 @@ EightBit::BigEndianProcessor::BigEndianProcessor(Bus& memory) : Processor(memory) {} EightBit::register16_t EightBit::BigEndianProcessor::getWord() { - const auto high = busRead(); + const auto high = memoryRead(); ++BUS().ADDRESS(); - const auto low = busRead(); + const auto low = memoryRead(); return { low, high }; } void EightBit::BigEndianProcessor::setWord(const register16_t value) { - busWrite(value.high); + memoryWrite(value.high); ++BUS().ADDRESS(); - busWrite(value.low); + memoryWrite(value.low); } EightBit::register16_t EightBit::BigEndianProcessor::getWordPaged(const uint8_t page, const uint8_t offset) { const auto high = getBytePaged(page, offset); ++BUS().ADDRESS().low; - const auto low = busRead(); + const auto low = memoryRead(); return { low, high }; } void EightBit::BigEndianProcessor::setWordPaged(const uint8_t page, const uint8_t offset, const register16_t value) { setBytePaged(page, offset, value.high); ++BUS().ADDRESS().low; - busWrite(value.low); + memoryWrite(value.low); } EightBit::register16_t EightBit::BigEndianProcessor::fetchWord() { diff --git a/src/InputOutput.cpp b/src/InputOutput.cpp index fe866ea..6ea37ef 100644 --- a/src/InputOutput.cpp +++ b/src/InputOutput.cpp @@ -1,31 +1,43 @@ #include "stdafx.h" #include "InputOutput.h" -uint8_t EightBit::InputOutput::readInputPort(const uint8_t port) { - OnReadingPort(port); - const auto value = m_input[port]; - OnReadPort(port); - return value; +#include + +#include "Register.h" + +size_t EightBit::InputOutput::size() const { + return 0x100; } -void EightBit::InputOutput::writeOutputPort(const uint8_t port, const uint8_t value) { - OnWritingPort(port); - m_output[port] = value; - OnWrittenPort(port); +uint8_t EightBit::InputOutput::peek(uint16_t) const { + throw std::logic_error("Peek operation not allowed."); } -void EightBit::InputOutput::OnReadingPort(uint8_t port) { - ReadingPort.fire(port); +uint8_t& EightBit::InputOutput::reference(uint16_t address) { + const auto port = register16_t(address).low; + switch (getAccessType()) { + case AccessType::Reading: + return m_input.reference(port); + case AccessType::Writing: + return m_output.reference(port); + case AccessType::Unknown: + default: + throw std::logic_error("Unknown I/O access type."); + } } -void EightBit::InputOutput::OnReadPort(uint8_t port) { - ReadPort.fire(port); +int EightBit::InputOutput::load(std::ifstream&, int, int, int) { + throw std::logic_error("load operation not allowed."); } -void EightBit::InputOutput::OnWritingPort(uint8_t port) { - WritingPort.fire(port); +int EightBit::InputOutput::load(const std::string&, int, int, int) { + throw std::logic_error("load operation not allowed."); } -void EightBit::InputOutput::OnWrittenPort(uint8_t port) { - WrittenPort.fire(port); +int EightBit::InputOutput::load(const std::vector&, int, int, int) { + throw std::logic_error("load operation not allowed."); +} + +void EightBit::InputOutput::poke(uint16_t, uint8_t) { + throw std::logic_error("Poke operation not allowed."); } diff --git a/src/IntelProcessor.cpp b/src/IntelProcessor.cpp index 8d72336..90f7af9 100644 --- a/src/IntelProcessor.cpp +++ b/src/IntelProcessor.cpp @@ -23,11 +23,11 @@ void EightBit::IntelProcessor::handleRESET() { } void EightBit::IntelProcessor::push(const uint8_t value) { - busWrite(--SP(), value); + memoryWrite(--SP(), value); } uint8_t EightBit::IntelProcessor::pop() { - return busRead(SP()++); + return memoryRead(SP()++); } EightBit::register16_t EightBit::IntelProcessor::getWord() { diff --git a/src/LittleEndianProcessor.cpp b/src/LittleEndianProcessor.cpp index 3b78fa5..d0e356f 100644 --- a/src/LittleEndianProcessor.cpp +++ b/src/LittleEndianProcessor.cpp @@ -5,29 +5,29 @@ EightBit::LittleEndianProcessor::LittleEndianProcessor(Bus& memory) : Processor(memory) {} EightBit::register16_t EightBit::LittleEndianProcessor::getWord() { - const auto low = busRead(); + const auto low = memoryRead(); ++BUS().ADDRESS(); - const auto high = busRead(); + const auto high = memoryRead(); return { low, high }; } void EightBit::LittleEndianProcessor::setWord(const register16_t value) { - busWrite(value.low); + memoryWrite(value.low); ++BUS().ADDRESS(); - busWrite(value.high); + memoryWrite(value.high); } EightBit::register16_t EightBit::LittleEndianProcessor::getWordPaged(const uint8_t page, const uint8_t offset) { const auto low = getBytePaged(page, offset); ++BUS().ADDRESS().low; - const auto high = busRead(); + const auto high = memoryRead(); return { low, high }; } void EightBit::LittleEndianProcessor::setWordPaged(const uint8_t page, const uint8_t offset, const register16_t value) { setBytePaged(page, offset, value.low); ++BUS().ADDRESS().low; - busWrite(value.high); + memoryWrite(value.high); } EightBit::register16_t EightBit::LittleEndianProcessor::fetchWord() { diff --git a/src/Processor.cpp b/src/Processor.cpp index 951e587..fcce6e9 100644 --- a/src/Processor.cpp +++ b/src/Processor.cpp @@ -16,13 +16,17 @@ void EightBit::Processor::handleINT() { raiseINT(); } -void EightBit::Processor::busWrite(const register16_t address, const uint8_t data) { +void EightBit::Processor::memoryWrite(const register16_t address, const uint8_t data) { BUS().ADDRESS() = address; - busWrite(data); + memoryWrite(data); } -void EightBit::Processor::busWrite(const uint8_t data) { +void EightBit::Processor::memoryWrite(const uint8_t data) { BUS().DATA() = data; + memoryWrite(); +} + +void EightBit::Processor::memoryWrite() { busWrite(); } @@ -30,8 +34,12 @@ void EightBit::Processor::busWrite() { BUS().write(); } -uint8_t EightBit::Processor::busRead(const register16_t address) { +uint8_t EightBit::Processor::memoryRead(const register16_t address) { BUS().ADDRESS() = address; + return memoryRead(); +} + +uint8_t EightBit::Processor::memoryRead() { return busRead(); }