diff --git a/core/broadway.cpp b/core/broadway.cpp index 785e924..d61ff8d 100644 --- a/core/broadway.cpp +++ b/core/broadway.cpp @@ -22,7 +22,7 @@ void broadway::run(mem &mem) { } ircolib::u32 broadway::fetch(mem &mem) { - ircolib::u32 val = mem.read(pc); + ircolib::u32 val = mem.read32(pc); pc += 4; return val; @@ -48,6 +48,12 @@ void broadway::execute(ircolib::u32 instr, mem &mem) { case 31: // mfspr rd, spr move_spr(instr); break; + case 32: // mfspr rd, spr + lwz(instr, mem); + break; + case 36: // stw rs, d(ra) + stw(instr, mem); + break; case 37: // stwu rs, d(ra) stwu(instr, mem); break; diff --git a/core/broadway.hpp b/core/broadway.hpp index c754e82..dafb379 100644 --- a/core/broadway.hpp +++ b/core/broadway.hpp @@ -30,7 +30,9 @@ struct broadway { void bx(ircolib::u32); void bcx(ircolib::u32); void move_spr(ircolib::u32); + void stw(ircolib::u32, mem &); void stwu(ircolib::u32, mem &); void sth(ircolib::u32, mem &); + void lwz(ircolib::u32, mem &); }; } // namespace weee::core diff --git a/core/broadway/instructions.cpp b/core/broadway/instructions.cpp index 1188a01..e9422f7 100644 --- a/core/broadway/instructions.cpp +++ b/core/broadway/instructions.cpp @@ -118,12 +118,20 @@ void broadway::stwu(ircolib::u32 instr, mem &mem) { if (utils::RA(instr) == 0) ircolib::panic("broadway::stwu with ra == 0"); - const ircolib::s32 d = utils::SIMM(instr); - const ircolib::u32 EA = gpr[utils::RA(instr)] + d; - mem.write(EA, gpr[utils::RS(instr)]); + const ircolib::u32 EA = ircolib::s32(gpr[utils::RA(instr)]) + utils::SIMM(instr); + mem.write32(EA, gpr[utils::RS(instr)]); gpr[utils::RA(instr)] = EA; } +void broadway::stw(ircolib::u32 instr, mem &mem) { + ircolib::s32 b = gpr[utils::RA(instr)]; + if (utils::RA(instr) == 0) + b = 0; + + const ircolib::u32 EA = b + utils::SIMM(instr); + mem.write32(EA, gpr[utils::RS(instr)]); +} + void broadway::sth(ircolib::u32 instr, mem &mem) { ircolib::u32 b = gpr[utils::RA(instr)]; if (utils::RA(instr) == 0) @@ -132,6 +140,15 @@ void broadway::sth(ircolib::u32 instr, mem &mem) { const ircolib::s32 d = utils::SIMM(instr); const ircolib::u32 EA = b + d; - mem.write(EA, ircolib::u16(gpr[utils::RS(instr)])); + mem.write16(EA, ircolib::u16(gpr[utils::RS(instr)])); +} + +void broadway::lwz(ircolib::u32 instr, mem &mem) { + ircolib::u32 b = gpr[utils::RA(instr)]; + if (utils::RA(instr) == 0) + b = 0; + + ircolib::u32 ea = ircolib::s32(b) + utils::SIMM(instr); + gpr[utils::RD(instr)] = mem.read32(ea); } } // namespace weee::core diff --git a/core/broadway/mmio/vi.cpp b/core/broadway/mmio/vi.cpp index 75e92e4..eaa1283 100644 --- a/core/broadway/mmio/vi.cpp +++ b/core/broadway/mmio/vi.cpp @@ -1,15 +1,53 @@ #include -#include "ircolib/log.hpp" +#include +#include namespace weee::core { -void video_interface::write(ircolib::u32 addr, ircolib::u16 value) { - addr -= 0x0c002000; +video_interface::video_interface(mem &mem) { + mem.register_write16_handler(0x0c002000, 0x0c0020ff, + [&](ircolib::u32 addr, ircolib::u16 value) { write16(addr, value); }); + mem.register_write32_handler(0x0c002000, 0x0c0020ff, + [&](ircolib::u32 addr, ircolib::u32 value) { write32(addr, value); }); +} + +void video_interface::write16(ircolib::u32 addr, ircolib::u16 value) { switch (addr) { - case 2: + case 0x00: + vtr.raw = value; + break; + case 0x02: dcr.raw = value; break; default: - ircolib::panic("video_interface::write to unimplemented addr 0x{:04X} with value 0x{:04X}", addr, value); + ircolib::panic("video_interface::write16 to unimplemented addr 0x{:04X} with value 0x{:04X}", addr, value); + } +} + +void video_interface::write32(ircolib::u32 addr, ircolib::u32 value) { + switch (addr) { + case 0x02: + dcr.raw = value; + break; + case 0x04: + htr0.raw = value; + break; + case 0x08: + htr1.raw = value; + break; + case 0x0c: + vto.raw = value; + break; + case 0x10: + vte.raw = value; + break; + case 0x14: + bbei.raw = value; + break; + case 0x18: + bboi.raw = value; + break; + default: + ircolib::panic("video_interface::write32 to unimplemented addr 0x{:04X} with value 0x{:08X}", addr, value); } } } // namespace weee::core diff --git a/core/broadway/mmio/vi.hpp b/core/broadway/mmio/vi.hpp index 49e11f6..4828af7 100644 --- a/core/broadway/mmio/vi.hpp +++ b/core/broadway/mmio/vi.hpp @@ -2,25 +2,82 @@ #include namespace weee::core { -union DCR { - struct { - unsigned e : 1; - unsigned r : 1; - unsigned i : 1; - unsigned d : 1; - unsigned le0 : 2; - unsigned le1 : 2; - unsigned fmt : 2; - unsigned : 6; - }; - - ircolib::u16 raw; -}; +struct mem; struct video_interface { - void write(ircolib::u32, ircolib::u16); + video_interface(mem &); + void write16(ircolib::u32, ircolib::u16); + void write32(ircolib::u32, ircolib::u32); - private: - DCR dcr{}; + union DCR { + struct { + unsigned e : 1; + unsigned r : 1; + unsigned i : 1; + unsigned d : 1; + unsigned le0 : 2; + unsigned le1 : 2; + unsigned fmt : 2; + unsigned : 6; + }; + + ircolib::u16 raw; + } dcr; + + union HTR0 { + struct { + unsigned hlw : 9; + unsigned : 7; + unsigned hce : 7; + unsigned : 1; + unsigned hcs : 7; + unsigned : 1; + }; + + ircolib::u32 raw; + } htr0; + + union HTR1 { + struct { + unsigned hsy : 7; + unsigned hbe : 10; + unsigned hbs : 10; + unsigned : 5; + }; + + ircolib::u32 raw; + } htr1; + + union VTR { + struct { + unsigned equ : 4; + unsigned acv : 10; + unsigned : 2; + }; + + ircolib::u16 raw; + } vtr; + + union VTO { + struct { + unsigned prb : 10; + unsigned : 6; + unsigned psb : 10; + unsigned : 6; + }; + + ircolib::u32 raw; + } vto, vte; + + union BBI { + struct { + unsigned bs1 : 5; + unsigned be1 : 11; + unsigned bs3 : 5; + unsigned be3 : 11; + }; + + ircolib::u32 raw; + } bbei, bboi; }; } // namespace weee::core diff --git a/core/loaders/dol.cpp b/core/loaders/dol.cpp index bd533fc..0535724 100644 --- a/core/loaders/dol.cpp +++ b/core/loaders/dol.cpp @@ -4,7 +4,6 @@ #include #include #include -#include namespace weee::core { bool load_dol(const std::string &path, mem &mem, broadway &broadway) { @@ -22,22 +21,22 @@ bool load_dol(const std::string &path, mem &mem, broadway &broadway) { } hdr; for (size_t bin_index = 0; bin_index < 0xD8; bin_index += 4) { - if (ircolib::is_inside_range_ext(bin_index, 0, 0x1c)) // text file offsets + if (ircolib::is_inside_range(bin_index, 0, 0x1b)) // text file offsets hdr.text[bin_index / 4].offset = std::byteswap(ircolib::read_access(bin, bin_index)); - if (ircolib::is_inside_range_ext(bin_index, 0x1c, 0x48)) // data file offsets + if (ircolib::is_inside_range(bin_index, 0x1c, 0x47)) // data file offsets hdr.data[(bin_index - 0x1c) / 4].offset = std::byteswap(ircolib::read_access(bin, bin_index)); - if (ircolib::is_inside_range_ext(bin_index, 0x48, 0x64)) // text loading addresses + if (ircolib::is_inside_range(bin_index, 0x48, 0x63)) // text loading addresses hdr.text[(bin_index - 0x48) / 4].addr = std::byteswap(ircolib::read_access(bin, bin_index)); - if (ircolib::is_inside_range_ext(bin_index, 0x64, 0x90)) // data loading addresses + if (ircolib::is_inside_range(bin_index, 0x64, 0x8f)) // data loading addresses hdr.data[(bin_index - 0x64) / 4].addr = std::byteswap(ircolib::read_access(bin, bin_index)); - if (ircolib::is_inside_range_ext(bin_index, 0x90, 0xac)) // text sizes + if (ircolib::is_inside_range(bin_index, 0x90, 0xab)) // text sizes hdr.text[(bin_index - 0x90) / 4].size = std::byteswap(ircolib::read_access(bin, bin_index)); - if (ircolib::is_inside_range_ext(bin_index, 0xac, 0xd8)) // data sizes + if (ircolib::is_inside_range(bin_index, 0xac, 0xd7)) // data sizes hdr.data[(bin_index - 0xac) / 4].size = std::byteswap(ircolib::read_access(bin, bin_index)); } diff --git a/core/mem.cpp b/core/mem.cpp index 61253af..6d39b36 100644 --- a/core/mem.cpp +++ b/core/mem.cpp @@ -4,9 +4,22 @@ #include "ircolib/mem_access.hpp" namespace weee::core { -mem::mem() { +mem::mem() : vi(*this) { mem1.resize(24_mib); std::fill(mem1.begin(), mem1.end(), 0); + register_read16_handler(0x00000000, 0x017fffff, + [&](ircolib::u32 addr) { return ircolib::read_access(mem1, addr); }); + + register_read32_handler(0x00000000, 0x017fffff, + [&](ircolib::u32 addr) { return ircolib::read_access(mem1, addr); }); + + register_write16_handler(0x00000000, 0x017fffff, [&](ircolib::u32 addr, ircolib::u16 value) { + ircolib::write_access(mem1, addr, value); + }); + + register_write32_handler(0x00000000, 0x017fffff, [&](ircolib::u32 addr, ircolib::u32 value) { + ircolib::write_access(mem1, addr, value); + }); } void mem::copy(std::vector &src, const ircolib::u32 offset) { @@ -14,7 +27,6 @@ void mem::copy(std::vector &src, const ircolib::u32 offset) { ircolib::panic("mem::copy outside mem1 range (src @ 0x{:08} for size 0x{:08X})", offset, src.size()); ircolib::swap_buffer(src); - std::println("Copying {} bytes to mem1[{}]", src.size(), offset); std::copy(src.begin(), src.end(), mem1.begin() + offset); } @@ -23,7 +35,6 @@ void mem::copy(ircolib::u8 *src, const ircolib::u32 size, const ircolib::u32 off ircolib::panic("mem::copy outside mem1 range (src @ 0x{:08} for size 0x{:08X})", offset, size); ircolib::swap_buffer(src, size); - std::println("Copying {} bytes to mem1[{}]", size, offset); memcpy(&mem1[offset], src, size); } @@ -31,46 +42,98 @@ void mem::set(const ircolib::u8 val, const ircolib::u32 size, const ircolib::u32 if (offset + size >= mem1.size()) ircolib::panic("mem::set outside mem1 range (@ 0x{:08} for size 0x{:08X})", offset, size); - std::println("Setting {} bytes to {} from mem1[{}]", size, val, offset); memset(&mem1[offset], val, size); } -template <> -ircolib::u32 mem::read(ircolib::u32 addr) { +ircolib::u8 mem::read8(ircolib::u32 addr) { addr &= 0x0FFFFFFF; - if (addr > 0x017FFFFF) - ircolib::panic("mem::read unimplemented outside mem1 (0x{:08X})", addr); - - return ircolib::read_access(mem1, addr); -} - -template <> -ircolib::u16 mem::read(ircolib::u32 addr) { - addr &= 0x0FFFFFFF; - if (addr > 0x017FFFFF) - ircolib::panic("mem::read unimplemented outside mem1 (0x{:08X})", addr); - - return ircolib::read_access(mem1, addr); -} - -void mem::write(ircolib::u32 addr, ircolib::u32 value) { - addr &= 0x0FFFFFFF; - if (addr > 0x017FFFFF) - ircolib::panic("mem::write unimplemented outside mem1 (0x{:08X} = 0x{:08X})", addr, value); - - ircolib::write_access(mem1, addr, value); -} - -void mem::write(ircolib::u32 addr, ircolib::u16 value) { - addr &= 0x0FFFFFFF; - if (addr > 0x017FFFFF && !ircolib::is_inside_range(addr, 0x0C002000, 0x0C0020FF)) - ircolib::panic("mem::write unimplemented outside mem1 and vi (0x{:08X} = 0x{:08X})", addr, value); - - if (addr <= 0x017FFFFF) { - ircolib::write_access(mem1, addr, value); - return; + for (const auto &handler : read8_handlers) { + if (ircolib::is_inside_range(addr, handler.start, handler.end)) { + return handler.func(addr - handler.start); + } } - vi.write(addr, value); + ircolib::panic("mem::read8 unimplemented addr 0x{:08X}", addr); + return 0; +} + +ircolib::u16 mem::read16(ircolib::u32 addr) { + addr &= 0x0FFFFFFF; + for (const auto &handler : read16_handlers) { + if (ircolib::is_inside_range(addr, handler.start, handler.end)) { + return handler.func(addr - handler.start); + } + } + + ircolib::panic("mem::read16 unimplemented addr 0x{:08X}", addr); + return 0; +} + +ircolib::u32 mem::read32(ircolib::u32 addr) { + addr &= 0x0FFFFFFF; + for (const auto &handler : read32_handlers) { + if (ircolib::is_inside_range(addr, handler.start, handler.end)) { + return handler.func(addr - handler.start); + } + } + + ircolib::panic("mem::read32 unimplemented addr 0x{:08X}", addr); + return 0; +} + +ircolib::u64 mem::read64(ircolib::u32 addr) { + addr &= 0x0FFFFFFF; + for (const auto &handler : read64_handlers) { + if (ircolib::is_inside_range(addr, handler.start, handler.end)) { + return handler.func(addr - handler.start); + } + } + + ircolib::panic("mem::read64 unimplemented addr 0x{:08X}", addr); + return 0; +} + +void mem::write8(ircolib::u32 addr, ircolib::u8 value) { + addr &= 0x0FFFFFFF; + for (const auto &handler : write8_handlers) { + if (ircolib::is_inside_range(addr, handler.start, handler.end)) { + return handler.func(addr - handler.start, value); + } + } + + ircolib::panic("mem::write8 unimplemented addr 0x{:08X} = 0x{:02X}", addr, value); +} + +void mem::write16(ircolib::u32 addr, ircolib::u16 value) { + addr &= 0x0FFFFFFF; + for (const auto &handler : write16_handlers) { + if (ircolib::is_inside_range(addr, handler.start, handler.end)) { + return handler.func(addr - handler.start, value); + } + } + + ircolib::panic("mem::write16 unimplemented addr 0x{:08X} = 0x{:04X}", addr, value); +} + +void mem::write32(ircolib::u32 addr, ircolib::u32 value) { + addr &= 0x0FFFFFFF; + for (const auto &handler : write32_handlers) { + if (ircolib::is_inside_range(addr, handler.start, handler.end)) { + return handler.func(addr - handler.start, value); + } + } + + ircolib::panic("mem::write32 unimplemented addr 0x{:08X} = 0x{:08X}", addr, value); +} + +void mem::write64(ircolib::u32 addr, ircolib::u64 value) { + addr &= 0x0FFFFFFF; + for (const auto &handler : write64_handlers) { + if (ircolib::is_inside_range(addr, handler.start, handler.end)) { + return handler.func(addr - handler.start, value); + } + } + + ircolib::panic("mem::write64 unimplemented addr 0x{:08X} = 0x{:016X}", addr, value); } } // namespace weee::core diff --git a/core/mem.hpp b/core/mem.hpp index 4371348..3b5b315 100644 --- a/core/mem.hpp +++ b/core/mem.hpp @@ -1,21 +1,81 @@ #pragma once #include #include -#include "broadway/mmio/vi.hpp" +#include +#include namespace weee::core { +template +struct read_handler { + std::function func; + ircolib::u32 start, end; +}; + +template +struct write_handler { + std::function func; + ircolib::u32 start, end; +}; + struct mem { mem(); - template - T read(ircolib::u32); - void write(ircolib::u32, ircolib::u32); - void write(ircolib::u32, ircolib::u16); + void register_read8_handler(ircolib::u32 start, ircolib::u32 end, + const std::function &func) { + read8_handlers.push_back({std::move(func), start, end}); + } + void register_read16_handler(ircolib::u32 start, ircolib::u32 end, + const std::function &func) { + read16_handlers.push_back({std::move(func), start, end}); + } + void register_read32_handler(ircolib::u32 start, ircolib::u32 end, + const std::function &func) { + read32_handlers.push_back({std::move(func), start, end}); + } + void register_read64_handler(ircolib::u32 start, ircolib::u32 end, + const std::function &func) { + read64_handlers.push_back({std::move(func), start, end}); + } + void register_write8_handler(ircolib::u32 start, ircolib::u32 end, + const std::function &func) { + write8_handlers.push_back({std::move(func), start, end}); + } + void register_write16_handler(ircolib::u32 start, ircolib::u32 end, + const std::function &func) { + write16_handlers.push_back({std::move(func), start, end}); + } + void register_write32_handler(ircolib::u32 start, ircolib::u32 end, + const std::function &func) { + write32_handlers.push_back({std::move(func), start, end}); + } + void register_write64_handler(ircolib::u32 start, ircolib::u32 end, + const std::function &func) { + write64_handlers.push_back({std::move(func), start, end}); + } + + ircolib::u8 read8(ircolib::u32); + ircolib::u16 read16(ircolib::u32); + ircolib::u32 read32(ircolib::u32); + ircolib::u64 read64(ircolib::u32); + void write8(ircolib::u32, ircolib::u8); + void write16(ircolib::u32, ircolib::u16); + void write32(ircolib::u32, ircolib::u32); + void write64(ircolib::u32, ircolib::u64); + void copy(std::vector &src, const ircolib::u32 offset); void copy(ircolib::u8 *src, const ircolib::u32 size, const ircolib::u32 offset); void set(const ircolib::u8 val, const ircolib::u32 size, const ircolib::u32 offset); private: + std::vector> read8_handlers{}; + std::vector> read16_handlers{}; + std::vector> read32_handlers{}; + std::vector> read64_handlers{}; + std::vector> write8_handlers{}; + std::vector> write16_handlers{}; + std::vector> write32_handlers{}; + std::vector> write64_handlers{}; + std::vector mem1; video_interface vi; }; diff --git a/external/ircolib/mem_access.hpp b/external/ircolib/mem_access.hpp index 05d8d97..bb83b77 100644 --- a/external/ircolib/mem_access.hpp +++ b/external/ircolib/mem_access.hpp @@ -30,11 +30,6 @@ static inline constexpr bool is_inside_range(const std::integral auto &addr, con return addr >= start && addr <= end; } -static inline constexpr bool is_inside_range_ext(const std::integral auto &addr, const std::integral auto &start, - const std::integral auto &end) { - return addr >= start && addr < end; -} - template static constexpr inline T read_access(const u8 *data, const u32 index); template