diff --git a/apps/target/main.cc b/apps/target/main.cc index a0c26b4..c019f2a 100644 --- a/apps/target/main.cc +++ b/apps/target/main.cc @@ -87,12 +87,14 @@ main(int argc, const char* argv[]) { matar::set_log_level(matar::LogLevel::Debug); try { - std::shared_ptr bus( - new matar::Bus(std::move(bios), std::move(rom))); + std::shared_ptr bus = + matar::Bus::init(std::move(bios), std::move(rom)); + matar::Cpu cpu(bus); + while (true) { cpu.step(); - std::this_thread::sleep_for(std::chrono::seconds(1)); + // std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } catch (const std::exception& e) { std::cerr << "Exception: " << e.what() << std::endl; diff --git a/include/bus.hh b/include/bus.hh index 61c7cce..2d1c607 100644 --- a/include/bus.hh +++ b/include/bus.hh @@ -2,41 +2,51 @@ #include "header.hh" #include "io/io.hh" +#include #include #include #include namespace matar { class Bus { + private: + struct Private { + explicit Private() = default; + }; + public: static constexpr uint32_t BIOS_SIZE = 1024 * 16; - Bus(std::array&& bios, std::vector&& rom); - uint8_t read_byte(uint32_t address); - void write_byte(uint32_t address, uint8_t byte); + Bus(Private, std::array&&, std::vector&&); - uint16_t read_halfword(uint32_t address); - void write_halfword(uint32_t address, uint16_t halfword); + static std::shared_ptr init(std::array&&, + std::vector&&); - uint32_t read_word(uint32_t address); - void write_word(uint32_t address, uint32_t word); + uint8_t read_byte(uint32_t); + void write_byte(uint32_t, uint8_t); + + uint16_t read_halfword(uint32_t); + void write_halfword(uint32_t, uint16_t); + + uint32_t read_word(uint32_t); + void write_word(uint32_t, uint32_t); private: - template - std::optional> read(uint32_t address) const; + template + std::optional> read(uint32_t) const; - template - std::optional> write(uint32_t address); + template + std::optional> write(uint32_t); #define MEMORY_REGION(name, start) \ static constexpr uint32_t name##_START = start; #define DECL_MEMORY(name, ident, start, end) \ MEMORY_REGION(name, start) \ - std::array ident; + std::array ident = {}; MEMORY_REGION(BIOS, 0x00000000) - std::array bios; + std::array bios = {}; // board working RAM DECL_MEMORY(BOARD_WRAM, board_wram, 0x02000000, 0x0203FFFF) @@ -61,9 +71,10 @@ class Bus { #undef MEMORY_REGION std::vector rom; + + std::unique_ptr io; + Header header; void parse_header(); - - IoDevices io; }; } diff --git a/include/cpu/cpu.hh b/include/cpu/cpu.hh index c67e1d9..2f176c4 100644 --- a/include/cpu/cpu.hh +++ b/include/cpu/cpu.hh @@ -30,10 +30,10 @@ class Cpu { static constexpr uint8_t GPR_OLD_FIRST = 8; std::shared_ptr bus; - std::array gpr; // general purpose registers + std::array gpr = {}; // general purpose registers - Psr cpsr; // current program status register - Psr spsr; // status program status register + Psr cpsr = {}; // current program status register + Psr spsr = {}; // status program status register static constexpr uint8_t SP_INDEX = 13; static_assert(SP_INDEX < GPR_COUNT); @@ -56,7 +56,7 @@ class Cpu { // visible registers before the mode switch std::array old; - } gpr_banked; // banked general purpose registers + } gpr_banked = {}; // banked general purpose registers struct { Psr fiq; diff --git a/include/io/io.hh b/include/io/io.hh index e22c7a1..bddb440 100644 --- a/include/io/io.hh +++ b/include/io/io.hh @@ -2,10 +2,14 @@ #include "lcd.hh" #include "sound.hh" #include +#include namespace matar { +class Bus; class IoDevices { public: + IoDevices(std::weak_ptr); + uint8_t read_byte(uint32_t) const; void write_byte(uint32_t, uint8_t); @@ -28,5 +32,7 @@ class IoDevices { struct lcd lcd = {}; struct sound sound = {}; + + std::weak_ptr bus; }; } diff --git a/src/bus.cc b/src/bus.cc index b3843cb..33649a7 100644 --- a/src/bus.cc +++ b/src/bus.cc @@ -7,13 +7,10 @@ namespace matar { static constexpr uint32_t IO_START = 0x4000000; static constexpr uint32_t IO_END = 0x40003FE; -Bus::Bus(std::array&& bios, std::vector&& rom) +Bus::Bus(Private, + std::array&& bios, + std::vector&& rom) : bios(std::move(bios)) - , board_wram({ 0 }) - , chip_wram({ 0 }) - , palette_ram({ 0 }) - , vram({ 0 }) - , oam_obj_attr({ 0 }) , rom(std::move(rom)) { std::string bios_hash = crypto::sha256(this->bios); static constexpr std::string_view expected_hash = @@ -33,6 +30,14 @@ Bus::Bus(std::array&& bios, std::vector&& rom) glogger.info("Cartridge Title: {}", header.title); }; +std::shared_ptr +Bus::init(std::array&& bios, std::vector&& rom) { + auto self = + std::make_shared(Private(), std::move(bios), std::move(rom)); + self->io = std::make_unique(self); + return self; +} + template std::optional> Bus::read(uint32_t address) const { @@ -78,7 +83,7 @@ Bus::write(uint32_t address) { uint8_t Bus::read_byte(uint32_t address) { if (address >= IO_START && address <= IO_END) - return io.read_byte(address); + return io->read_byte(address); auto data = read<1>(address); return data.transform([](auto value) { return value[0]; }).value_or(0xFF); @@ -87,7 +92,7 @@ Bus::read_byte(uint32_t address) { void Bus::write_byte(uint32_t address, uint8_t byte) { if (address >= IO_START && address <= IO_END) { - io.write_byte(address, byte); + io->write_byte(address, byte); return; } @@ -103,7 +108,7 @@ Bus::read_halfword(uint32_t address) { glogger.warn("Reading a non aligned halfword address"); if (address >= IO_START && address <= IO_END) - return io.read_halfword(address); + return io->read_halfword(address); return read<2>(address) .transform([](auto value) { return value[0] | value[1] << 8; }) @@ -116,7 +121,7 @@ Bus::write_halfword(uint32_t address, uint16_t halfword) { glogger.warn("Writing to a non aligned halfword address"); if (address >= IO_START && address <= IO_END) { - io.write_halfword(address, halfword); + io->write_halfword(address, halfword); return; } @@ -135,7 +140,7 @@ Bus::read_word(uint32_t address) { glogger.warn("Reading a non aligned word address"); if (address >= IO_START && address <= IO_END) - return io.read_word(address); + return io->read_word(address); return read<4>(address) .transform([](auto value) { @@ -150,7 +155,7 @@ Bus::write_word(uint32_t address, uint32_t word) { glogger.warn("Writing to a non aligned word address"); if (address >= IO_START && address <= IO_END) { - io.write_word(address, word); + io->write_word(address, word); return; } diff --git a/src/io/io.cc b/src/io/io.cc index 9d1794d..22153a0 100644 --- a/src/io/io.cc +++ b/src/io/io.cc @@ -86,6 +86,9 @@ ADDR HALTCNT = 0x4000301; #undef ADDR +IoDevices::IoDevices(std::weak_ptr bus) + : bus(bus) {} + uint8_t IoDevices::read_byte(uint32_t address) const { uint16_t halfword = read_halfword(address & ~1); diff --git a/tests/bus.cc b/tests/bus.cc index 723a32b..32cdcdb 100644 --- a/tests/bus.cc +++ b/tests/bus.cc @@ -8,11 +8,11 @@ using namespace matar; class BusFixture { public: BusFixture() - : bus(std::array(), - std::vector(Header::HEADER_SIZE)) {} + : bus(Bus::init(std::array(), + std::vector(Header::HEADER_SIZE))) {} protected: - Bus bus; + std::shared_ptr bus; }; TEST_CASE("bios", TAG) { @@ -23,66 +23,67 @@ TEST_CASE("bios", TAG) { bios[0x3FFF] = 0x48; bios[0x2A56] = 0x10; - Bus bus(std::move(bios), std::vector(Header::HEADER_SIZE)); + auto bus = + Bus::init(std::move(bios), std::vector(Header::HEADER_SIZE)); - CHECK(bus.read_byte(0) == 0xAC); - CHECK(bus.read_byte(0x3FFF) == 0x48); - CHECK(bus.read_byte(0x2A56) == 0x10); + CHECK(bus->read_byte(0) == 0xAC); + CHECK(bus->read_byte(0x3FFF) == 0x48); + CHECK(bus->read_byte(0x2A56) == 0x10); } TEST_CASE_METHOD(BusFixture, "board wram", TAG) { - bus.write_byte(0x2000000, 0xAC); - CHECK(bus.read_byte(0x2000000) == 0xAC); + bus->write_byte(0x2000000, 0xAC); + CHECK(bus->read_byte(0x2000000) == 0xAC); - bus.write_byte(0x203FFFF, 0x48); - CHECK(bus.read_byte(0x203FFFF) == 0x48); + bus->write_byte(0x203FFFF, 0x48); + CHECK(bus->read_byte(0x203FFFF) == 0x48); - bus.write_byte(0x2022A56, 0x10); - CHECK(bus.read_byte(0x2022A56) == 0x10); + bus->write_byte(0x2022A56, 0x10); + CHECK(bus->read_byte(0x2022A56) == 0x10); } TEST_CASE_METHOD(BusFixture, "chip wram", TAG) { - bus.write_byte(0x3000000, 0xAC); - CHECK(bus.read_byte(0x3000000) == 0xAC); + bus->write_byte(0x3000000, 0xAC); + CHECK(bus->read_byte(0x3000000) == 0xAC); - bus.write_byte(0x3007FFF, 0x48); - CHECK(bus.read_byte(0x3007FFF) == 0x48); + bus->write_byte(0x3007FFF, 0x48); + CHECK(bus->read_byte(0x3007FFF) == 0x48); - bus.write_byte(0x3002A56, 0x10); - CHECK(bus.read_byte(0x3002A56) == 0x10); + bus->write_byte(0x3002A56, 0x10); + CHECK(bus->read_byte(0x3002A56) == 0x10); } TEST_CASE_METHOD(BusFixture, "palette ram", TAG) { - bus.write_byte(0x5000000, 0xAC); - CHECK(bus.read_byte(0x5000000) == 0xAC); + bus->write_byte(0x5000000, 0xAC); + CHECK(bus->read_byte(0x5000000) == 0xAC); - bus.write_byte(0x50003FF, 0x48); - CHECK(bus.read_byte(0x50003FF) == 0x48); + bus->write_byte(0x50003FF, 0x48); + CHECK(bus->read_byte(0x50003FF) == 0x48); - bus.write_byte(0x5000156, 0x10); - CHECK(bus.read_byte(0x5000156) == 0x10); + bus->write_byte(0x5000156, 0x10); + CHECK(bus->read_byte(0x5000156) == 0x10); } TEST_CASE_METHOD(BusFixture, "video ram", TAG) { - bus.write_byte(0x6000000, 0xAC); - CHECK(bus.read_byte(0x6000000) == 0xAC); + bus->write_byte(0x6000000, 0xAC); + CHECK(bus->read_byte(0x6000000) == 0xAC); - bus.write_byte(0x6017FFF, 0x48); - CHECK(bus.read_byte(0x6017FFF) == 0x48); + bus->write_byte(0x6017FFF, 0x48); + CHECK(bus->read_byte(0x6017FFF) == 0x48); - bus.write_byte(0x6012A56, 0x10); - CHECK(bus.read_byte(0x6012A56) == 0x10); + bus->write_byte(0x6012A56, 0x10); + CHECK(bus->read_byte(0x6012A56) == 0x10); } TEST_CASE_METHOD(BusFixture, "oam obj ram", TAG) { - bus.write_byte(0x7000000, 0xAC); - CHECK(bus.read_byte(0x7000000) == 0xAC); + bus->write_byte(0x7000000, 0xAC); + CHECK(bus->read_byte(0x7000000) == 0xAC); - bus.write_byte(0x70003FF, 0x48); - CHECK(bus.read_byte(0x70003FF) == 0x48); + bus->write_byte(0x70003FF, 0x48); + CHECK(bus->read_byte(0x70003FF) == 0x48); - bus.write_byte(0x7000156, 0x10); - CHECK(bus.read_byte(0x7000156) == 0x10); + bus->write_byte(0x7000156, 0x10); + CHECK(bus->read_byte(0x7000156) == 0x10); } TEST_CASE("rom", TAG) { @@ -94,43 +95,43 @@ TEST_CASE("rom", TAG) { rom[0x0EF0256] = 0x10; // 32 megabyte ROM - Bus bus(std::array(), std::move(rom)); + auto bus = Bus::init(std::array(), std::move(rom)); SECTION("ROM1") { - CHECK(bus.read_byte(0x8000000) == 0xAC); - CHECK(bus.read_byte(0x9FFFFFF) == 0x48); - CHECK(bus.read_byte(0x8EF0256) == 0x10); + CHECK(bus->read_byte(0x8000000) == 0xAC); + CHECK(bus->read_byte(0x9FFFFFF) == 0x48); + CHECK(bus->read_byte(0x8EF0256) == 0x10); } SECTION("ROM2") { - CHECK(bus.read_byte(0xA000000) == 0xAC); - CHECK(bus.read_byte(0xBFFFFFF) == 0x48); - CHECK(bus.read_byte(0xAEF0256) == 0x10); + CHECK(bus->read_byte(0xA000000) == 0xAC); + CHECK(bus->read_byte(0xBFFFFFF) == 0x48); + CHECK(bus->read_byte(0xAEF0256) == 0x10); } SECTION("ROM3") { - CHECK(bus.read_byte(0xC000000) == 0xAC); - CHECK(bus.read_byte(0xDFFFFFF) == 0x48); - CHECK(bus.read_byte(0xCEF0256) == 0x10); + CHECK(bus->read_byte(0xC000000) == 0xAC); + CHECK(bus->read_byte(0xDFFFFFF) == 0x48); + CHECK(bus->read_byte(0xCEF0256) == 0x10); } } TEST_CASE_METHOD(BusFixture, "Halfword", TAG) { - CHECK(bus.read_halfword(0x202FED9) == 0); + CHECK(bus->read_halfword(0x202FED9) == 0); - bus.write_halfword(0x202FED9, 0x1A4A); - CHECK(bus.read_halfword(0x202FED9) == 0x1A4A); - CHECK(bus.read_word(0x202FED9) == 0x1A4A); - CHECK(bus.read_byte(0x202FED9) == 0x4A); + bus->write_halfword(0x202FED9, 0x1A4A); + CHECK(bus->read_halfword(0x202FED9) == 0x1A4A); + CHECK(bus->read_word(0x202FED9) == 0x1A4A); + CHECK(bus->read_byte(0x202FED9) == 0x4A); } TEST_CASE_METHOD(BusFixture, "Word", TAG) { - CHECK(bus.read_word(0x600EE34) == 0); + CHECK(bus->read_word(0x600EE34) == 0); - bus.write_word(0x600EE34, 0x3ACC491D); - CHECK(bus.read_word(0x600EE34) == 0x3ACC491D); - CHECK(bus.read_halfword(0x600EE34) == 0x491D); - CHECK(bus.read_byte(0x600EE34) == 0x1D); + bus->write_word(0x600EE34, 0x3ACC491D); + CHECK(bus->read_word(0x600EE34) == 0x3ACC491D); + CHECK(bus->read_halfword(0x600EE34) == 0x491D); + CHECK(bus->read_byte(0x600EE34) == 0x1D); } #undef TAG diff --git a/tests/cpu/cpu-fixture.hh b/tests/cpu/cpu-fixture.hh index 4abef5a..2350375 100644 --- a/tests/cpu/cpu-fixture.hh +++ b/tests/cpu/cpu-fixture.hh @@ -5,9 +5,8 @@ using namespace matar; class CpuFixture { public: CpuFixture() - : bus(std::shared_ptr( - new Bus(std::array(), - std::vector(Header::HEADER_SIZE)))) + : bus(Bus::init(std::array(), + std::vector(Header::HEADER_SIZE))) , cpu(bus) {} protected: