Don't expose the bus via the CPU any more: if a component needs the bus, it should be prepared to hold a reference to it.

Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon 2018-10-20 20:52:41 +01:00
parent 9b0cc4542f
commit 1b2ddd8843
19 changed files with 131 additions and 103 deletions

View File

@ -5,12 +5,14 @@
#include <sstream>
#include <boost/format.hpp>
#include <Intel8080.h>
#include <Bus.h>
#include "Intel8080.h"
namespace EightBit {
class Disassembler {
public:
Disassembler() noexcept;
Disassembler(Bus& bus) noexcept;
static std::string state(Intel8080& cpu);
std::string disassemble(Intel8080& cpu);
@ -25,6 +27,7 @@ namespace EightBit {
private:
mutable boost::format m_formatter;
Bus& m_bus;
void disassemble(std::ostringstream& output, Intel8080& cpu, uint16_t pc);
@ -43,5 +46,7 @@ namespace EightBit {
static std::string cc(int flag);
static std::string alu(int which);
static std::string alu2(int which);
Bus& BUS() { return m_bus; }
};
}

View File

@ -8,7 +8,8 @@
#include <iomanip>
#include <bitset>
EightBit::Disassembler::Disassembler() noexcept {
EightBit::Disassembler::Disassembler(Bus& bus) noexcept
: m_bus(bus) {
// Disable exceptions where too many format arguments are available
m_formatter.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
}
@ -168,8 +169,7 @@ std::string EightBit::Disassembler::disassemble(Intel8080& cpu) {
void EightBit::Disassembler::disassemble(std::ostringstream& output, Intel8080& cpu, uint16_t pc) {
auto& bus = cpu.BUS();
auto opcode = bus.peek(pc);
auto opcode = BUS().peek(pc);
output << hex(opcode);
@ -180,11 +180,11 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, Intel8080&
auto p = (y & 0b110) >> 1;
auto q = (y & 1);
auto immediate = bus.peek(pc + 1);
auto immediate = BUS().peek(pc + 1);
auto absolute = cpu.peekWord(pc + 1).word;
auto displacement = (int8_t)immediate;
auto relative = pc + displacement + 2;
auto indexedImmediate = bus.peek(pc + 1);
auto indexedImmediate = BUS().peek(pc + 1);
auto dumpCount = 0;
@ -196,7 +196,7 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, Intel8080&
x, y, z, p, q);
for (int i = 0; i < dumpCount; ++i)
output << hex(bus.peek(pc + i + 1));
output << hex(BUS().peek(pc + i + 1));
output << '\t';
m_formatter.parse(specification);

View File

@ -6,7 +6,8 @@
Board::Board(const Configuration& configuration)
: m_configuration(configuration),
m_cpu(EightBit::Intel8080(*this, m_ports)) {
m_cpu(EightBit::Intel8080(*this, m_ports)),
m_disassembler(*this) {
}
void Board::initialise() {

View File

@ -157,7 +157,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.BUS().peek(address);
auto actual = peek(address);
if (expected != actual) {
m_failed = true;
if (first) {

View File

@ -5,6 +5,8 @@
#include <sstream>
#include <boost/format.hpp>
#include "GameBoyBus.h"
namespace EightBit {
namespace GameBoy {
@ -13,7 +15,7 @@ namespace EightBit {
class Disassembler {
public:
Disassembler() noexcept;
Disassembler(Bus& bus) noexcept;
static std::string state(LR35902& cpu);
std::string disassemble(LR35902& cpu);
@ -36,6 +38,8 @@ namespace EightBit {
Unused, // Unused!
};
Bus& m_bus;
mutable boost::format m_formatter;
bool m_prefixCB = false;
@ -65,6 +69,8 @@ namespace EightBit {
std::string R(int r) const;
static std::string cc(int flag);
static std::string alu(int which);
Bus& BUS() { return m_bus; }
};
}
}

View File

@ -4,6 +4,7 @@
#include <cstdint>
#include "Disassembler.h"
#include "GameBoyBus.h"
namespace EightBit {
namespace GameBoy {
@ -12,7 +13,7 @@ namespace EightBit {
class Profiler {
public:
Profiler(LR35902& cpu);
Profiler(Bus& bus, LR35902& cpu);
void add(uint16_t address, uint8_t instruction);
@ -21,8 +22,8 @@ namespace EightBit {
private:
std::array<uint64_t, 0x100> m_instructions;
std::array<uint64_t, 0x10000> m_addresses;
Bus& m_bus;
LR35902& m_cpu;
Disassembler m_disassembler;
void dumpInstructionProfiles() const;

View File

@ -9,7 +9,8 @@
#include "LR35902.h"
#include "IoRegisters.h"
EightBit::GameBoy::Disassembler::Disassembler() noexcept {
EightBit::GameBoy::Disassembler::Disassembler(Bus& bus) noexcept
: m_bus(bus) {
// Disable exceptions where too many format arguments are available
m_formatter.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
}
@ -148,8 +149,7 @@ std::string EightBit::GameBoy::Disassembler::disassemble(LR35902& cpu) {
void EightBit::GameBoy::Disassembler::disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc) {
auto& bus = cpu.BUS();
auto opcode = bus.peek(pc);
auto opcode = BUS().peek(pc);
// hex opcode
output << hex(opcode);
@ -161,11 +161,11 @@ void EightBit::GameBoy::Disassembler::disassemble(std::ostringstream& output, LR
auto p = (y & 0b110) >> 1;
auto q = (y & 1);
auto immediate = bus.peek(pc + 1);
auto immediate = BUS().peek(pc + 1);
auto absolute = cpu.peekWord(pc + 1).word;
auto displacement = (int8_t)immediate;
auto relative = pc + displacement + 2;
auto indexedImmediate = bus.peek(pc + 1);
auto indexedImmediate = BUS().peek(pc + 1);
auto dumpCount = 0;
auto ioRegister = IoRegister::Unused;
@ -184,7 +184,7 @@ void EightBit::GameBoy::Disassembler::disassemble(std::ostringstream& output, LR
x, y, z, p, q);
for (int i = 0; i < dumpCount; ++i)
output << hex(bus.peek(pc + i + 1));
output << hex(BUS().peek(pc + i + 1));
output << '\t';
m_formatter.parse(specification);

View File

@ -2,8 +2,10 @@
#include "Profiler.h"
#include "LR35902.h"
EightBit::GameBoy::Profiler::Profiler(LR35902& cpu)
: m_cpu(cpu) {
EightBit::GameBoy::Profiler::Profiler(Bus& bus, LR35902& cpu)
: m_bus(bus),
m_cpu(cpu),
m_disassembler(bus) {
std::fill(m_instructions.begin(), m_instructions.end(), 0);
std::fill(m_addresses.begin(), m_addresses.end(), 0);
}

View File

@ -9,15 +9,16 @@
namespace EightBit {
class Disassembly {
public:
Disassembly(MOS6502& processor, const Symbols& symbols);
Disassembly(Bus& bus, MOS6502& processor, const Symbols& symbols);
std::string disassemble(uint16_t current) const;
std::string disassemble(uint16_t current);
static std::string dump_Flags(uint8_t value);
static std::string dump_ByteValue(uint8_t value);
static std::string dump_WordValue(uint16_t value);
private:
Bus& m_bus;
MOS6502& processor;
const Symbols& symbols;
@ -27,119 +28,119 @@ namespace EightBit {
return "\t" + instruction;
}
std::string disassemble_Absolute(const std::string& instruction) const {
std::string disassemble_Absolute(const std::string& instruction) {
return AM_Absolute_dump() + "\t" + instruction + " " + AM_Absolute();
}
std::string disassemble_Indirect(const std::string& instruction) const {
std::string disassemble_Indirect(const std::string& instruction) {
return AM_Absolute_dump() + "\t" + instruction + " (" + AM_Absolute() + ")";
}
std::string disassemble_Relative(const std::string& instruction, uint16_t address) const {
std::string disassemble_Relative(const std::string& instruction, uint16_t address) {
return AM_Immediate_dump() + "\t" + instruction + " $" + dump_WordValue(address);
}
std::string disassemble_Immediate(const std::string& instruction) const {
std::string disassemble_Immediate(const std::string& instruction) {
return AM_Immediate_dump() + "\t" + instruction + " " + AM_Immediate();
}
std::string disassemble_AM_00(int bbb, const std::string& instruction) const {
std::string disassemble_AM_00(int bbb, const std::string& instruction) {
return AM_00_dump(bbb) + "\t" + instruction + " " + AM_00(bbb);
}
std::string disassemble_AM_01(int bbb, const std::string& instruction) const {
std::string disassemble_AM_01(int bbb, const std::string& instruction) {
return AM_01_dump(bbb) + "\t" + instruction + " " + AM_01(bbb);
}
std::string disassemble_AM_10(int bbb, const std::string& instruction) const {
std::string disassemble_AM_10(int bbb, const std::string& instruction) {
return AM_10_dump(bbb) + "\t" + instruction + " " + AM_10(bbb);
}
std::string disassemble_AM_10_x(int bbb, const std::string& instruction) const {
std::string disassemble_AM_10_x(int bbb, const std::string& instruction) {
return AM_10_x_dump(bbb) + "\t" + instruction + " " + AM_10_x(bbb);
}
std::string disassemble_AM_11(int bbb, const std::string& instruction) const {
std::string disassemble_AM_11(int bbb, const std::string& instruction) {
return AM_11_dump(bbb) + "\t" + instruction + " " + AM_11(bbb);
}
std::string disassemble_AM_11_x(int bbb, const std::string& instruction) const {
std::string disassemble_AM_11_x(int bbb, const std::string& instruction) {
return AM_11_x_dump(bbb) + "\t" + instruction + " " + AM_11_x(bbb);
}
std::string AM_Immediate_dump() const {
std::string AM_Immediate_dump() {
return dump_Byte(m_address + 1);
}
std::string AM_Immediate() const {
std::string AM_Immediate() {
return "#$" + AM_Immediate_dump();
}
std::string AM_Absolute_dump() const {
std::string AM_Absolute_dump() {
return dump_DByte(m_address + 1);
}
std::string AM_Absolute() const {
std::string AM_Absolute() {
return "$" + dump_Word(m_address + 1);
}
std::string AM_ZeroPage_dump() const {
std::string AM_ZeroPage_dump() {
return dump_Byte(m_address + 1);
}
std::string AM_ZeroPage() const {
std::string AM_ZeroPage() {
return "$" + dump_Byte(m_address + 1);
}
std::string AM_ZeroPageX_dump() const {
std::string AM_ZeroPageX_dump() {
return AM_ZeroPage_dump();
}
std::string AM_ZeroPageX() const {
std::string AM_ZeroPageX() {
return AM_ZeroPage() + ",X";
}
std::string AM_ZeroPageY_dump() const {
std::string AM_ZeroPageY_dump() {
return AM_ZeroPage_dump();
}
std::string AM_ZeroPageY() const {
std::string AM_ZeroPageY() {
return AM_ZeroPage() + ",Y";
}
std::string AM_AbsoluteX_dump() const {
std::string AM_AbsoluteX_dump() {
return AM_Absolute_dump();
}
std::string AM_AbsoluteX() const {
std::string AM_AbsoluteX() {
return AM_Absolute() + ",X";
}
std::string AM_AbsoluteY_dump() const {
std::string AM_AbsoluteY_dump() {
return AM_Absolute_dump();
}
std::string AM_AbsoluteY() const {
std::string AM_AbsoluteY() {
return AM_Absolute() + ",Y";
}
std::string AM_IndexedIndirectX_dump() const {
std::string AM_IndexedIndirectX_dump() {
return AM_ZeroPage_dump();
}
std::string AM_IndexedIndirectX() const {
std::string AM_IndexedIndirectX() {
return "($" + dump_Byte(m_address + 1) + ",X)";
}
std::string AM_IndirectIndexedY_dump() const {
std::string AM_IndirectIndexedY_dump() {
return AM_ZeroPage_dump();
}
std::string AM_IndirectIndexedY() const {
std::string AM_IndirectIndexedY() {
return "($" + dump_Byte(m_address + 1) + "),Y";
}
std::string AM_00_dump(int bbb) const {
std::string AM_00_dump(int bbb) {
switch (bbb) {
case 0b000:
return AM_Immediate_dump();
@ -160,7 +161,7 @@ namespace EightBit {
}
}
std::string AM_00(int bbb) const {
std::string AM_00(int bbb) {
switch (bbb) {
case 0b000:
return AM_Immediate();
@ -181,7 +182,7 @@ namespace EightBit {
}
}
std::string AM_01_dump(int bbb) const {
std::string AM_01_dump(int bbb) {
switch (bbb) {
case 0b000:
return AM_IndexedIndirectX_dump();
@ -204,7 +205,7 @@ namespace EightBit {
}
}
std::string AM_01(int bbb) const {
std::string AM_01(int bbb) {
switch (bbb) {
case 0b000:
return AM_IndexedIndirectX();
@ -227,7 +228,7 @@ namespace EightBit {
}
}
std::string AM_10_dump(int bbb) const {
std::string AM_10_dump(int bbb) {
switch (bbb) {
case 0b000:
return AM_Immediate_dump();
@ -249,7 +250,7 @@ namespace EightBit {
}
}
std::string AM_10(int bbb) const {
std::string AM_10(int bbb) {
switch (bbb) {
case 0b000:
return AM_Immediate();
@ -271,7 +272,7 @@ namespace EightBit {
}
}
std::string AM_10_x_dump(int bbb) const {
std::string AM_10_x_dump(int bbb) {
switch (bbb) {
case 0b000:
return AM_Immediate_dump();
@ -293,7 +294,7 @@ namespace EightBit {
}
}
std::string AM_10_x(int bbb) const {
std::string AM_10_x(int bbb) {
switch (bbb) {
case 0b000:
return AM_Immediate();
@ -315,7 +316,7 @@ namespace EightBit {
}
}
std::string AM_11_dump(int bbb) const {
std::string AM_11_dump(int bbb) {
switch (bbb) {
case 0b000:
return AM_IndexedIndirectX_dump();
@ -338,7 +339,7 @@ namespace EightBit {
}
}
std::string AM_11_x_dump(int bbb) const {
std::string AM_11_x_dump(int bbb) {
switch (bbb) {
case 0b000:
return AM_IndexedIndirectX_dump();
@ -361,7 +362,7 @@ namespace EightBit {
}
}
std::string AM_11(int bbb) const {
std::string AM_11(int bbb) {
switch (bbb) {
case 0b000:
return AM_IndexedIndirectX();
@ -384,7 +385,7 @@ namespace EightBit {
}
}
std::string AM_11_x(int bbb) const {
std::string AM_11_x(int bbb) {
switch (bbb) {
case 0b000:
return AM_IndexedIndirectX();
@ -409,16 +410,18 @@ namespace EightBit {
static void dump(std::ostream& out, int value, int width);
uint8_t getByte(uint16_t address) const;
uint16_t getWord(uint16_t address) const;
uint8_t getByte(uint16_t address);
uint16_t getWord(uint16_t address);
std::string dump_Byte(uint16_t address) const;
std::string dump_DByte(uint16_t address) const;
std::string dump_Word(uint16_t address) const;
std::string dump_Byte(uint16_t address);
std::string dump_DByte(uint16_t address);
std::string dump_Word(uint16_t address);
std::string convertAddress(uint16_t address) const;
std::string convertAddress(uint8_t address) const;
std::string convertConstant(uint16_t constant) const;
std::string convertConstant(uint16_t constant);
std::string convertConstant(uint8_t constant) const;
Bus& BUS() { return m_bus; }
};
}

View File

@ -27,7 +27,7 @@ namespace EightBit {
std::map<std::string, uint64_t> scopeCycles;
MOS6502& processor;
const Disassembly& disassembler;
Disassembly& disassembler;
const Symbols& symbols;
Profiler(MOS6502& processor, Disassembly& disassembler, Symbols& symbols);

View File

@ -7,8 +7,9 @@
using namespace std::placeholders;
EightBit::Disassembly::Disassembly(MOS6502& targetProcessor, const Symbols& targetSymbols)
: processor(targetProcessor),
EightBit::Disassembly::Disassembly(Bus& bus, MOS6502& targetProcessor, const Symbols& targetSymbols)
: m_bus(bus),
processor(targetProcessor),
symbols(targetSymbols) {
}
@ -41,19 +42,17 @@ std::string EightBit::Disassembly::dump_WordValue(uint16_t value) {
return output.str();
}
std::string EightBit::Disassembly::disassemble(uint16_t current) const {
std::string EightBit::Disassembly::disassemble(uint16_t current) {
m_address = current;
std::ostringstream output;
auto& bus = processor.BUS();
auto cell = bus.peek(current);
auto cell = BUS().peek(current);
output << dump_ByteValue(cell) << " ";
auto byte = bus.peek(current + 1);
auto byte = BUS().peek(current + 1);
uint16_t relative = processor.PC().word + 2 + (int8_t)byte;
auto aaa = (cell & 0b11100000) >> 5;
@ -468,25 +467,25 @@ std::string EightBit::Disassembly::disassemble(uint16_t current) const {
////
uint8_t EightBit::Disassembly::getByte(uint16_t address) const {
return processor.BUS().peek(address);
uint8_t EightBit::Disassembly::getByte(uint16_t address) {
return BUS().peek(address);
}
uint16_t EightBit::Disassembly::getWord(uint16_t address) const {
uint16_t EightBit::Disassembly::getWord(uint16_t address) {
return processor.peekWord(address).word;
}
////
std::string EightBit::Disassembly::dump_Byte(uint16_t address) const {
std::string EightBit::Disassembly::dump_Byte(uint16_t address) {
return dump_ByteValue(getByte(address));
}
std::string EightBit::Disassembly::dump_DByte(uint16_t address) const {
std::string EightBit::Disassembly::dump_DByte(uint16_t address) {
return dump_Byte(address) + " " + dump_Byte(address + 1);
}
std::string EightBit::Disassembly::dump_Word(uint16_t address) const {
std::string EightBit::Disassembly::dump_Word(uint16_t address) {
return dump_WordValue(getWord(address));
}
@ -510,7 +509,7 @@ std::string EightBit::Disassembly::convertAddress(uint8_t address) const {
return output.str();
}
std::string EightBit::Disassembly::convertConstant(uint16_t constant) const {
std::string EightBit::Disassembly::convertConstant(uint16_t constant) {
auto label = symbols.getConstants().find(constant);
if (label != symbols.getConstants().end())
return label->second;

View File

@ -10,7 +10,7 @@
Board::Board(const Configuration& configuration)
: m_configuration(configuration),
m_cpu(EightBit::MOS6502(*this)),
m_disassembler(m_cpu, m_symbols),
m_disassembler(*this, m_cpu, m_symbols),
m_profiler(m_cpu, m_disassembler, m_symbols) {}
void Board::initialise() {
@ -74,12 +74,12 @@ void Board::Cpu_ExecutingInstruction_Profile(const EightBit::MOS6502& cpu) {
void Board::Cpu_ExecutedInstruction_StopLoop(EightBit::MOS6502& cpu) {
auto pc = cpu.PC().word;
if (m_oldPC == pc) {
if (m_oldPC != pc) {
m_oldPC = pc;
} else {
CPU().powerOff();
auto test = peek(0x0200);
std::cout << std::endl << "** Test=" << std::hex << (int)test;
} else {
m_oldPC = pc;
}
}

View File

@ -3,12 +3,14 @@
#include <cstdint>
#include <string>
#include <Bus.h>
#include "mc6809.h"
namespace EightBit {
class Disassembly final {
public:
Disassembly(mc6809& processor);
Disassembly(Bus& bus, mc6809& processor);
bool ignore();
@ -17,6 +19,7 @@ namespace EightBit {
std::string trace();
private:
Bus& m_bus;
mc6809& m_cpu;
mutable uint16_t m_address = 0xffff;
@ -80,5 +83,7 @@ namespace EightBit {
std::string pshU();
std::string pulX(std::string mnemomic, std::string upon);
std::string pshX(std::string mnemomic, std::string upon);
Bus& BUS() { return m_bus; }
};
}

View File

@ -8,8 +8,9 @@
using namespace std::placeholders;
EightBit::Disassembly::Disassembly(mc6809& targetProcessor)
: m_cpu(targetProcessor) {
EightBit::Disassembly::Disassembly(Bus& bus, mc6809& targetProcessor)
: m_bus(bus),
m_cpu(targetProcessor) {
}
std::string EightBit::Disassembly::dump_Flags(uint8_t value) {
@ -878,7 +879,7 @@ std::string EightBit::Disassembly::tfr(std::string mnemomic) {
////
uint8_t EightBit::Disassembly::getByte(uint16_t address) {
return CPU().BUS().peek(address);
return BUS().peek(address);
}
uint16_t EightBit::Disassembly::getWord(uint16_t address) {

View File

@ -4,7 +4,7 @@
Board::Board(const Configuration& configuration)
: m_configuration(configuration),
m_cpu(EightBit::mc6809(*this)),
m_disassembler(m_cpu) {
m_disassembler(*this, m_cpu) {
std::vector<uint8_t> content(m_unused2000.size());
std::fill(content.begin(), content.end(), 0xff);
m_unused2000.load(content);

View File

@ -2,14 +2,15 @@
#include <string>
#include <boost/format.hpp>
#include <Bus.h>
namespace EightBit {
class Z80;
class Disassembler {
class Disassembler final {
public:
Disassembler() noexcept;
Disassembler(Bus& bus) noexcept;
static std::string state(Z80& cpu);
std::string disassemble(Z80& cpu);
@ -29,6 +30,7 @@ namespace EightBit {
bool m_prefixDD = false;
bool m_prefixED = false;
bool m_prefixFD = false;
Bus& m_bus;
void disassemble(std::ostringstream& output, Z80& cpu, uint16_t pc);
@ -64,5 +66,7 @@ namespace EightBit {
std::string R(int r) const;
static std::string cc(int flag);
static std::string alu(int which);
Bus& BUS() { return m_bus; }
};
}

View File

@ -10,7 +10,8 @@
#include "Z80.h"
EightBit::Disassembler::Disassembler() noexcept {
EightBit::Disassembler::Disassembler(Bus& bus) noexcept
: m_bus(bus) {
// Disable exceptions where too many format arguments are available
m_formatter.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
}
@ -180,8 +181,7 @@ std::string EightBit::Disassembler::disassemble(Z80& cpu) {
void EightBit::Disassembler::disassemble(std::ostringstream& output, Z80& cpu, uint16_t pc) {
auto& bus = cpu.BUS();
auto opcode = bus.peek(pc);
auto opcode = BUS().peek(pc);
const auto& decoded = cpu.getDecodedOpcode(opcode);
@ -192,11 +192,11 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, Z80& cpu, u
auto p = decoded.p;
auto q = decoded.q;
auto immediate = bus.peek(pc + 1);
auto immediate = BUS().peek(pc + 1);
auto absolute = cpu.peekWord(pc + 1).word;
auto displacement = (int8_t)immediate;
auto relative = pc + displacement + 2;
auto indexedImmediate = bus.peek(pc + 1);
auto indexedImmediate = BUS().peek(pc + 1);
auto dumpCount = 0;
@ -221,7 +221,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(bus.peek(pc + i + 1));
output << hex(BUS().peek(pc + i + 1));
auto outputFormatSpecification = !m_prefixDD;
if (m_prefixDD) {

View File

@ -6,6 +6,7 @@
Board::Board(const Configuration& configuration)
: m_configuration(configuration),
m_cpu(EightBit::Z80(*this, m_ports)),
m_disassembler(*this),
m_profiler(m_cpu, m_disassembler) {
}

View File

@ -15,8 +15,6 @@ namespace EightBit {
// x: sign extend this b-bit number to r
static int8_t signExtend(int b, uint8_t x);
Bus& BUS() { return m_bus; }
register16_t& PC() { return m_pc; }
PinLevel& RESET() { return m_resetLine; }
@ -40,6 +38,8 @@ namespace EightBit {
Processor(Bus& memory);
virtual ~Processor() = default;
Bus& BUS() { return m_bus; }
bool halted() { return lowered(HALT()); }
void halt() { --PC(); lower(HALT()); }
void proceed() { ++PC(); raise(HALT()); }