Ensure the Z80 unit tests run successfully to completion.

Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian.Conlon 2017-09-07 01:04:09 +01:00
parent c472d70c5c
commit cae34d61d1
9 changed files with 79 additions and 67 deletions

View File

@ -4,7 +4,7 @@
#include <string>
#include <fstream>
#include "Memory.h"
#include <Register.h>
namespace Fuse {
class RegisterState {

View File

@ -5,11 +5,10 @@
Fuse::TestRunner::TestRunner(const Test& test, const ExpectedTestResult& expected)
: m_test(test),
m_expected(expected),
m_memory(0xffff),
m_cpu(m_memory, m_ports),
m_ram(0x10000),
m_cpu(*this, m_ports),
m_failed(false),
m_unimplemented(false) {
m_memory.clear();
m_cpu.initialise();
}
@ -57,7 +56,7 @@ void Fuse::TestRunner::initialiseMemory() {
auto address = memoryDatum.address;
auto bytes = memoryDatum.bytes;
for (int i = 0; i < bytes.size(); ++i)
m_memory.poke(address + i, bytes[i]);
poke(address + i, bytes[i]);
}
}
@ -304,7 +303,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 = m_cpu.getMemory().peek(address);
auto actual = peek(address);
if (expected != actual) {
m_failed = true;
if (first) {

View File

@ -3,12 +3,13 @@
#include "FuseTest.h"
#include "FuseExpectedTestResult.h"
#include "Memory.h"
#include "InputOutput.h"
#include "Z80.h"
#include <Ram.h>
#include <Bus.h>
#include <InputOutput.h>
#include <Z80.h>
namespace Fuse {
class TestRunner {
class TestRunner : public EightBit::Bus {
private:
const Test& m_test;
const ExpectedTestResult& m_expected;
@ -16,7 +17,7 @@ namespace Fuse {
bool m_failed;
bool m_unimplemented;
EightBit::Memory m_memory;
EightBit::Ram m_ram;
EightBit::InputOutput m_ports;
EightBit::Z80 m_cpu;
@ -34,6 +35,12 @@ namespace Fuse {
const std::string& lowDescription,
EightBit::register16_t actual, EightBit::register16_t expected) const;
protected:
virtual uint8_t& reference(uint16_t address, bool& rom) {
rom = false;
return m_ram.reference(address);
}
public:
TestRunner(const Test& test, const ExpectedTestResult& expected);

View File

@ -42,7 +42,7 @@ namespace EightBit {
CF = Bit0,
};
Z80(Memory& memory, InputOutput& ports);
Z80(Bus& bus, InputOutput& ports);
Signal<Z80> ExecutingInstruction;

View File

@ -178,8 +178,8 @@ std::string EightBit::Disassembler::disassemble(Z80& cpu) {
void EightBit::Disassembler::disassemble(std::ostringstream& output, Z80& cpu, uint16_t pc) {
auto& memory = cpu.getMemory();
auto opcode = memory.peek(pc);
auto& bus = cpu.BUS();
auto opcode = bus.peek(pc);
const auto& decoded = cpu.getDecodedOpcode(opcode);
@ -190,11 +190,11 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, Z80& cpu, u
auto p = decoded.p;
auto q = decoded.q;
auto immediate = memory.peek(pc + 1);
auto absolute = memory.peekWord(pc + 1);
auto immediate = bus.peek(pc + 1);
auto absolute = bus.peekWord(pc + 1);
auto displacement = (int8_t)immediate;
auto relative = pc + displacement + 2;
auto indexedImmediate = memory.peek(pc + 1);
auto indexedImmediate = bus.peek(pc + 1);
auto dumpCount = 0;
@ -219,7 +219,7 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, Z80& cpu, u
x, y, z, p, q);
for (int i = 0; i < dumpCount; ++i)
output << hex(memory.peek(pc + i + 1));
output << hex(bus.peek(pc + i + 1));
auto outputFormatSpecification = !m_prefixDD;
if (m_prefixDD) {

View File

@ -5,8 +5,8 @@
#pragma region Reset and initialisation
EightBit::Z80::Z80(Memory& memory, InputOutput& ports)
: IntelProcessor(memory),
EightBit::Z80::Z80(Bus& bus, InputOutput& ports)
: IntelProcessor(bus),
m_ports(ports),
m_registerSet(0),
m_accumulatorFlagsSet(0),
@ -509,7 +509,7 @@ void EightBit::Z80::xhtl(register16_t& operand) {
MEMPTR().low = getByte(SP());
setByte(operand.low);
operand.low = MEMPTR().low;
m_memory.ADDRESS().word++;
BUS().ADDRESS().word++;
MEMPTR().high = getByte();
setByte(operand.high);
operand.high = MEMPTR().high;
@ -615,20 +615,20 @@ bool EightBit::Z80::lddr(uint8_t a, uint8_t& f) {
#pragma region Block input instructions
void EightBit::Z80::ini(uint8_t& f) {
MEMPTR() = m_memory.ADDRESS() = BC();
MEMPTR() = BUS().ADDRESS() = BC();
MEMPTR().word++;
readPort();
auto value = m_memory.DATA();
auto value = BUS().DATA();
setByte(HL().word++, value);
decrement(f, B());
setFlag(f, NF);
}
void EightBit::Z80::ind(uint8_t& f) {
MEMPTR() = m_memory.ADDRESS() = BC();
MEMPTR() = BUS().ADDRESS() = BC();
MEMPTR().word--;
readPort();
auto value = m_memory.DATA();
auto value = BUS().DATA();
setByte(HL().word--, value);
decrement(f, B());
setFlag(f, NF);
@ -650,7 +650,7 @@ bool EightBit::Z80::indr(uint8_t& f) {
void EightBit::Z80::blockOut(uint8_t& f) {
auto value = getByte();
m_memory.ADDRESS() = BC();
BUS().ADDRESS() = BC();
writePort();
decrement(f, B());
setFlag(f, NF, value & Bit7);
@ -659,13 +659,13 @@ void EightBit::Z80::blockOut(uint8_t& f) {
}
void EightBit::Z80::outi(uint8_t& f) {
m_memory.ADDRESS().word = HL().word++;
BUS().ADDRESS().word = HL().word++;
blockOut(f);
MEMPTR().word = BC().word + 1;
}
void EightBit::Z80::outd(uint8_t& f) {
m_memory.ADDRESS().word = HL().word--;
BUS().ADDRESS().word = HL().word--;
blockOut(f);
MEMPTR().word = BC().word - 1;
}
@ -711,29 +711,29 @@ void EightBit::Z80::rld(uint8_t& a, uint8_t& f) {
#pragma region I/O instructions
void EightBit::Z80::writePort(uint8_t port, uint8_t data) {
m_memory.ADDRESS().low = port;
m_memory.ADDRESS().high = data;
MEMPTR() = m_memory.ADDRESS();
m_memory.placeDATA(data);
BUS().ADDRESS().low = port;
BUS().ADDRESS().high = data;
MEMPTR() = BUS().ADDRESS();
BUS().placeDATA(data);
writePort();
MEMPTR().low++;
}
void EightBit::Z80::writePort() {
m_ports.write(m_memory.ADDRESS().low, m_memory.DATA());
m_ports.write(BUS().ADDRESS().low, BUS().DATA());
}
void EightBit::Z80::readPort(uint8_t port, uint8_t& a) {
m_memory.ADDRESS().low = port;
m_memory.ADDRESS().high = a;
MEMPTR() = m_memory.ADDRESS();
BUS().ADDRESS().low = port;
BUS().ADDRESS().high = a;
MEMPTR() = BUS().ADDRESS();
readPort();
a = m_memory.DATA();
a = BUS().DATA();
MEMPTR().low++;
}
void EightBit::Z80::readPort() {
m_memory.placeDATA(m_ports.read(m_memory.ADDRESS().low));
BUS().placeDATA(m_ports.read(BUS().ADDRESS().low));
}
#pragma endregion I/O instructions
@ -893,22 +893,22 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
case 1:
switch (z) {
case 0: // Input from port with 16-bit address
MEMPTR() = m_memory.ADDRESS() = BC();
MEMPTR() = BUS().ADDRESS() = BC();
MEMPTR().word++;
readPort();
if (y != 6) // IN r[y],(C)
R(y, a, m_memory.DATA());
adjustSZPXY<Z80>(f, m_memory.DATA());
R(y, a, BUS().DATA());
adjustSZPXY<Z80>(f, BUS().DATA());
clearFlag(f, NF | HC);
cycles += 12;
break;
case 1: // Output to port with 16-bit address
MEMPTR() = m_memory.ADDRESS() = BC();
MEMPTR() = BUS().ADDRESS() = BC();
MEMPTR().word++;
if (y == 6) // OUT (C),0
m_memory.placeDATA(0);
BUS().placeDATA(0);
else // OUT (C),r[y]
m_memory.placeDATA(R(y, a));
BUS().placeDATA(R(y, a));
writePort();
cycles += 12;
break;

View File

@ -4,23 +4,22 @@
Board::Board(const Configuration& configuration)
: m_configuration(configuration),
m_memory(0x3fff),
m_cpu(EightBit::Z80(m_memory, m_ports)),
m_ram(0x10000),
m_cpu(EightBit::Z80(*this, m_ports)),
m_profiler(m_cpu, m_disassembler) {
}
void Board::initialise() {
m_memory.clear();
auto romDirectory = m_configuration.getRomDirectory();
//m_memory.loadRam(romDirectory + "/prelim.com", 0x100); // Bartholomew preliminary
//m_memory.loadRam(romDirectory + "/zexdoc.com", 0x100); // Cringle/Bartholomew
m_memory.loadRam(romDirectory + "/zexall.com", 0x100); // Cringle/Bartholomew
//m_memory.loadRam(romDirectory + "/CPUTEST.COM", 0x100); // SuperSoft diagnostics
//m_memory.loadRam(romDirectory + "/TEST.COM", 0x100); // Microcosm
//m_ram.load(romDirectory + "/prelim.com", 0x100); // Bartholomew preliminary
//m_ram.load(romDirectory + "/zexdoc.com", 0x100); // Cringle/Bartholomew
m_ram.load(romDirectory + "/zexall.com", 0x100); // Cringle/Bartholomew
//m_ram.load(romDirectory + "/CPUTEST.COM", 0x100); // SuperSoft diagnostics
//m_ram.load(romDirectory + "/TEST.COM", 0x100); // Microcosm
m_memory.poke(5, 0xc9); // ret
poke(5, 0xc9); // ret
m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Cpm, this, std::placeholders::_1));
if (m_configuration.isProfileMode()) {
@ -61,8 +60,8 @@ void Board::bdos() {
break;
}
case 0x9:
for (uint16_t i = m_cpu.DE().word; m_memory.peek(i) != '$'; ++i) {
std::cout << m_memory.peek(i);
for (uint16_t i = m_cpu.DE().word; peek(i) != '$'; ++i) {
std::cout << peek(i);
}
break;
}
@ -73,7 +72,7 @@ void Board::Cpu_ExecutingInstruction_Profile(const EightBit::Z80& cpu) {
const auto pc = m_cpu.PC();
m_profiler.addAddress(pc.word);
m_profiler.addInstruction(m_memory.peek(pc.word));
m_profiler.addInstruction(peek(pc.word));
}
void Board::Cpu_ExecutingInstruction_Debug(const EightBit::Z80& cpu) {

View File

@ -2,26 +2,33 @@
#include <string>
#include "Memory.h"
#include "InputOutput.h"
#include "Configuration.h"
#include "Profiler.h"
#include "EventArgs.h"
#include "Disassembler.h"
#include "Z80.h"
#include <Ram.h>
#include <Bus.h>
#include <InputOutput.h>
#include <Profiler.h>
#include <EventArgs.h>
#include <Disassembler.h>
#include <Z80.h>
class Board {
#include "Configuration.h"
class Board : public EightBit::Bus {
public:
Board(const Configuration& configuration);
EightBit::Memory& Memory() { return m_memory; }
EightBit::Z80& CPU() { return m_cpu; }
void initialise();
protected:
virtual uint8_t& reference(uint16_t address, bool& rom) {
rom = false;
return m_ram.reference(address);
}
private:
const Configuration& m_configuration;
EightBit::Memory m_memory;
EightBit::Ram m_ram;
EightBit::InputOutput m_ports;
EightBit::Z80 m_cpu;
EightBit::Disassembler m_disassembler;

View File

@ -2,7 +2,7 @@
#include <string>
#include "Memory.h"
#include <Register.h>
class Configuration {
public: