Reflect that the I/O for Intel style processors isn't part of the CPU, but attached to the Bus and access controlled by the CPU.

Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon 2020-02-09 11:51:58 +00:00
parent dc37d61797
commit c8bdabf34f
24 changed files with 410 additions and 279 deletions

Binary file not shown.

View File

@ -6,7 +6,6 @@
#include <stdexcept>
#include <Bus.h>
#include <InputOutput.h>
#include <IntelProcessor.h>
#include <EventArgs.h>
#include <Signal.h>
@ -23,7 +22,7 @@ namespace EightBit {
CF = Bit0,
};
Intel8080(Bus& bus, InputOutput& ports);
Intel8080(Bus& bus);
Signal<Intel8080> ExecutingInstruction;
Signal<Intel8080> 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();
};
}

View File

@ -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

View File

@ -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) {
}

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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());
}

View File

@ -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());
}
//

View File

@ -2,12 +2,13 @@
#include "FuseTestRunner.h"
#include "Disassembler.h"
#include <stdexcept>
#include <boost/algorithm/string/predicate.hpp>
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) {

View File

@ -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);

View File

@ -5,7 +5,6 @@
#include <stdexcept>
#include <Bus.h>
#include <InputOutput.h>
#include <IntelProcessor.h>
#include <EventArgs.h>
#include <Signal.h>
@ -47,12 +46,11 @@ namespace EightBit {
CF = Bit0,
};
Z80(Bus& bus, InputOutput& ports);
Z80(Bus& bus);
Signal<Z80> ExecutingInstruction;
Signal<Z80> 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<std::array<register16_t, 3>, 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();
};
}

View File

@ -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<Z80>(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<Z80>(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<Z80>(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;

View File

@ -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;

View File

@ -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<class T> [[nodiscard]] auto read(const T address) {

View File

@ -4,36 +4,51 @@
#include <array>
#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<uint8_t>& bytes, int writeOffset = 0, int readOffset = 0, int limit = -1) override;
Signal<uint8_t> ReadingPort;
Signal<uint8_t> ReadPort;
AccessType getAccessType() const noexcept { return m_access; }
void setAccessType(AccessType value) noexcept { m_access = value; }
Signal<uint8_t> WritingPort;
Signal<uint8_t> 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<uint8_t, 0x100> m_input = { 0 };
std::array<uint8_t, 0x100> m_output = { 0 };
Ram m_input = 0x100;
Ram m_output = 0x100;
AccessType m_access = AccessType::Unknown;
};
}

View File

@ -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;

View File

@ -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')

View File

@ -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;

View File

@ -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() {

View File

@ -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 <stdexcept>
#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<uint8_t>&, 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.");
}

View File

@ -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() {

View File

@ -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() {

View File

@ -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();
}