there might be an off by 1 error...

This commit is contained in:
2026-05-18 17:42:02 +02:00
parent aeb5094b05
commit eee9fcfb17
6 changed files with 266 additions and 44 deletions
+1
View File
@@ -17,6 +17,7 @@ if(WIN32)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
add_compile_definitions(NOMINMAX)
endif()
add_compile_options(-fno-operator-names)
set(CAPSTONE_ARCHITECTURE_DEFAULT OFF)
set(CAPSTONE_PPC_SUPPORT ON)
+49 -1
View File
@@ -17,27 +17,66 @@ void broadway::set_pc(ircolib::u32 value) { pc = value; }
void broadway::run(mem &mem) {
for (int i = 0; i < 12150000; i++) {
// std::println("pc: 0x{:08X}", pc);
execute(fetch(mem), mem);
}
}
ircolib::u32 broadway::fetch(mem &mem) {
ircolib::u32 val = mem.read32(pc);
ircolib::u32 val = mem.read32(pc)
.and_then([&](ircolib::u32 val) { return std::expected<ircolib::u32, std::string>(val); })
.or_else([&](std::string e) {
ircolib::panic("broadway read failed. Reason {} (pc: 0x{:08X})", e, pc);
return std::expected<ircolib::u32, std::string>();
})
.value();
pc += 4;
return val;
}
void broadway::decode_special3(ircolib::u32 instr, mem &mem) {
auto secondary = utils::secondary(instr);
switch (secondary) {
case 38:
mtfsb1(instr);
break;
case 711:
mtfsf(instr);
break;
default:
ircolib::panic("broadway unknown special3 {} (0x{:04X}) (pc 0x{:08X})", secondary, secondary, pc - 4);
}
}
void broadway::decode_special2(ircolib::u32 instr, mem &mem) {
auto secondary = utils::secondary(instr);
switch (secondary) {
case 0x000:
cmp(instr);
break;
case 0x020:
cmpl(instr);
break;
case 0x028:
subf(instr);
break;
case 0x053:
mfmsr(instr);
break;
case 0x0D2:
ircolib::warn("broadway TODO mtsr (pc 0x{:08X})", pc - 4);
break;
case 0x1BC:
or (instr);
break;
case 0x153:
case 0x1D3:
mftspr(ircolib::is_bit_set<ircolib::u32, 7>(secondary), instr);
break;
case 0x1DC:
nand(instr);
break;
case 0x10A:
add(instr);
break;
@@ -66,6 +105,9 @@ void broadway::decode_special1(ircolib::u32 instr, mem &mem) {
void broadway::execute(ircolib::u32 instr, mem &mem) {
switch (utils::primary(instr)) {
case 10:
cmpli(instr);
break;
case 11:
cmpi(instr);
break;
@@ -111,12 +153,18 @@ void broadway::execute(ircolib::u32 instr, mem &mem) {
case 37:
stwu(instr, mem);
break;
case 39:
stbu(instr, mem);
break;
case 44:
sth(instr, mem);
break;
case 50:
lfd(instr, mem);
break;
case 63:
decode_special3(instr, mem);
break;
default:
std::println("broadway::execute unimplemented instruction 0x{:08X} / 0b{:032b}", instr, instr);
std::println("disassembly:");
+27 -2
View File
@@ -17,7 +17,7 @@ struct broadway {
void execute(ircolib::u32, mem &);
bool disasm_available = true;
ircolib::u32 pc = 0, lr = 0, ctr = 0, cr = 0, srr0;
ircolib::u32 pc = 0, lr = 0, ctr = 0, cr = 0, srr0 = 0, fpscr = 0, msr = 0;
union {
struct {
unsigned bytecount : 7;
@@ -43,7 +43,13 @@ struct broadway {
std::array<ircolib::u32, 16> ibat, dbat;
std::array<ircolib::u32, 32> gpr{};
std::array<double, 32> fpr{};
struct Fgr {
ircolib::u64 ps0, ps1;
};
std::array<Fgr, 32> fgrs{};
// ircolib::u32 const_gpr_lookup{};
csh capstone;
// Xbyak::CodeGenerator code;
@@ -51,6 +57,7 @@ struct broadway {
// instructions
void decode_special1(ircolib::u32, mem &);
void decode_special2(ircolib::u32, mem &);
void decode_special3(ircolib::u32, mem &);
void branch(bool, bool, ircolib::u32);
bool test_cond_and_ctr(ircolib::u32);
@@ -66,14 +73,25 @@ struct broadway {
void mftspr(bool, ircolib::u32);
void stw(ircolib::u32, mem &);
void stwu(ircolib::u32, mem &);
void stbu(ircolib::u32, mem &);
void sth(ircolib::u32, mem &);
void lwz(ircolib::u32, mem &);
void lfd(ircolib::u32, mem &);
void bclrx(ircolib::u32);
void cmpi(ircolib::u32);
void cmpli(ircolib::u32);
void cmp(ircolib::u32);
void cmpl(ircolib::u32);
void rlwinm(ircolib::u32);
void lwzu(ircolib::u32, mem &);
void rfi(ircolib::u32);
void mtfsf(ircolib::u32);
void mtfsb1(ircolib::u32);
void mtfsb0(ircolib::u32);
void mfmsr(ircolib::u32);
void nand(ircolib::u32);
void subf(ircolib::u32);
void or (ircolib::u32);
inline void cr0_update(bool condition, ircolib::s32 result) {
if (condition) {
@@ -84,5 +102,12 @@ struct broadway {
set_cr((b0 << 3) | (b1 << 2) | (b2 << 1) | (b3 << 0), 0);
}
}
inline void cr1_update(bool condition) {
if (condition) {
const ircolib::u8 field = (fpscr >> 28) & 0xf;
set_cr(field, 1);
}
}
};
} // namespace weee::core
+150 -9
View File
@@ -1,5 +1,5 @@
#include <broadway/utils.hpp>
#include "ircolib/log.hpp"
#include <broadway/utils.hpp>
#include <mem.hpp>
namespace weee::core {
@@ -49,6 +49,7 @@ void broadway::bx(ircolib::u32 instr) {
bool broadway::test_cond_and_ctr(ircolib::u32 instr) {
const ircolib::u8 bo = (instr >> 21) & 0x1f;
const ircolib::u8 bi = (instr >> 16) & 0x1f;
const bool ctr_ok = ircolib::is_bit_set(bo, 2) || ((--ctr == 0) == (ircolib::is_bit_set(bo, 1)));
const bool cond_ok = ircolib::is_bit_set(bo, 4) || (get_cr_bit(0, bi) == ircolib::is_bit_set(bo, 3));
@@ -132,7 +133,8 @@ void broadway::mftspr(bool dir, ircolib::u32 instr) {
move_to_or_from_spr(dbat[BAT_UPPER_OFFSET + 3]);
break;
default:
ircolib::warn("broadway::m{}spr with unimplemented spr field of value 0b{:010b} (0x{:04X}) (pc 0x{:08X})",
ircolib::warn("broadway::m{}spr with unimplemented spr field of value "
"0b{:010b} (0x{:04X}) (pc 0x{:08X})",
dir ? 't' : 'f', spr_field, spr_field, pc - 4);
}
}
@@ -142,7 +144,26 @@ void broadway::stwu(ircolib::u32 instr, mem &mem) {
ircolib::panic("broadway::stwu with ra == 0");
const ircolib::u32 EA = ircolib::s32(gpr[utils::RA(instr)]) + utils::SIMM(instr);
mem.write32(EA, gpr[utils::RS(instr)]);
auto _ = mem.write32(EA, gpr[utils::RS(instr)])
.and_then([&] { return std::expected<void, std::string>(); })
.or_else([&](std::string e) {
ircolib::panic("broadway write failed. Reason: {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<void, std::string>();
});
gpr[utils::RA(instr)] = EA;
}
void broadway::stbu(ircolib::u32 instr, mem &mem) {
if (utils::RA(instr) == 0)
ircolib::panic("broadway::stbu with ra == 0");
const ircolib::u32 EA = ircolib::s32(gpr[utils::RA(instr)]) + utils::SIMM(instr);
auto _ = mem.write8(EA, gpr[utils::RS(instr)])
.and_then([&] { return std::expected<void, std::string>(); })
.or_else([&](std::string e) {
ircolib::panic("broadway write failed. Reason: {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<void, std::string>();
});
gpr[utils::RA(instr)] = EA;
}
@@ -152,7 +173,12 @@ void broadway::stw(ircolib::u32 instr, mem &mem) {
b = 0;
const ircolib::u32 EA = b + utils::SIMM(instr);
mem.write32(EA, gpr[utils::RS(instr)]);
auto _ = mem.write32(EA, gpr[utils::RS(instr)])
.and_then([&] { return std::expected<void, std::string>(); })
.or_else([&](std::string e) {
ircolib::panic("broadway write failed. Reason: {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<void, std::string>();
});
}
void broadway::sth(ircolib::u32 instr, mem &mem) {
@@ -163,7 +189,12 @@ void broadway::sth(ircolib::u32 instr, mem &mem) {
const ircolib::s32 d = utils::SIMM(instr);
const ircolib::u32 EA = b + d;
mem.write16(EA, ircolib::u16(gpr[utils::RS(instr)]));
auto _ = mem.write16(EA, ircolib::u16(gpr[utils::RS(instr)]))
.and_then([&] { return std::expected<void, std::string>(); })
.or_else([&](std::string e) {
ircolib::panic("broadway write failed. Reason: {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<void, std::string>();
});
}
void broadway::lwz(ircolib::u32 instr, mem &mem) {
@@ -172,7 +203,14 @@ void broadway::lwz(ircolib::u32 instr, mem &mem) {
b = 0;
ircolib::u32 ea = ircolib::s32(b) + utils::SIMM(instr);
gpr[utils::RD(instr)] = mem.read32(ea);
gpr[utils::RD(instr)] = mem.read32(ea)
.and_then([&](ircolib::u32 val) { return std::expected<ircolib::u32, std::string>(val); })
.or_else([&](std::string e) {
ircolib::panic("broadway read failed. Reason {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<ircolib::u32, std::string>();
})
.value();
}
void broadway::lfd(ircolib::u32 instr, mem &mem) {
@@ -182,9 +220,15 @@ void broadway::lfd(ircolib::u32 instr, mem &mem) {
ircolib::u32 ea = ircolib::s32(b) + utils::SIMM(instr);
double val;
ircolib::u64 read = mem.read64(ea);
ircolib::u64 read = mem.read64(ea)
.and_then([&](ircolib::u64 val) { return std::expected<ircolib::u64, std::string>(val); })
.or_else([&](std::string e) {
ircolib::panic("broadway read failed. Reason {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<ircolib::u64, std::string>();
})
.value();
memcpy(&val, &read, 8);
fpr[utils::RD(instr)] = val;
fgrs[utils::RD(instr)].ps0 = val;
}
void broadway::bclrx(ircolib::u32 instr) {
@@ -211,6 +255,51 @@ void broadway::cmpi(ircolib::u32 instr) {
set_cr(result, utils::crfD(instr));
}
void broadway::cmpli(ircolib::u32 instr) {
const ircolib::u32 a = gpr[utils::RA(instr)];
const ircolib::u32 uimm = utils::UIMM(instr);
ircolib::u8 c;
if (a < uimm)
c = 0b001;
else if (a > uimm)
c = 0b010;
else
c = 0b100;
const ircolib::u8 result = (xer.so << 3) | c;
set_cr(result, utils::crfD(instr));
}
void broadway::cmp(ircolib::u32 instr) {
const ircolib::s32 a = gpr[utils::RA(instr)];
const ircolib::s32 b = gpr[utils::RB(instr)];
ircolib::u8 c;
if (a < b)
c = 0b001;
else if (a > b)
c = 0b010;
else
c = 0b100;
const ircolib::u8 result = (xer.so << 3) | c;
set_cr(result, utils::crfD(instr));
}
void broadway::cmpl(ircolib::u32 instr) {
const ircolib::u32 a = gpr[utils::RA(instr)];
const ircolib::u32 b = gpr[utils::RB(instr)];
ircolib::u8 c;
if (a < b)
c = 0b001;
else if (a > b)
c = 0b010;
else
c = 0b100;
const ircolib::u8 result = (xer.so << 3) | c;
set_cr(result, utils::crfD(instr));
}
void broadway::rlwinm(ircolib::u32 instr) {
const ircolib::u8 sh = (instr >> 11) & 0x1f;
ircolib::u32 r = std::rotl(gpr[utils::RS(instr)], sh);
@@ -226,7 +315,13 @@ void broadway::lwzu(ircolib::u32 instr, mem &mem) {
ircolib::panic("broadway::lwzu with ra == 0");
const ircolib::u32 EA = ircolib::s32(gpr[utils::RA(instr)]) + utils::SIMM(instr);
gpr[utils::RD(instr)] = mem.read32(EA);
gpr[utils::RD(instr)] = mem.read32(EA)
.and_then([&](ircolib::u32 val) { return std::expected<ircolib::u32, std::string>(val); })
.or_else([&](std::string e) {
ircolib::panic("broadway read failed. Reason {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<ircolib::u32, std::string>();
})
.value();
gpr[utils::RA(instr)] = EA;
}
@@ -237,4 +332,50 @@ void broadway::andi(ircolib::u32 instr) {
gpr[utils::RA(instr)] = result;
cr0_update(true, result);
}
void broadway::mtfsf(ircolib::u32 instr) {
const ircolib::u8 fm = (instr >> 17) & 0xff;
ircolib::u8 mask = 0;
for (int i = 0; i < 8; i++) {
if (ircolib::is_bit_set(fm, i)) {
mask |= 0xf << (i * 4);
}
}
ircolib::u32 frb = fgrs[utils::RB(instr)].ps0;
fpscr = (fpscr & ~mask) | (frb & mask);
cr1_update(instr & 1);
}
void broadway::mtfsb0(ircolib::u32 instr) {
ircolib::u32 mask = ~(1 << utils::RD(instr));
fpscr = fpscr & mask;
cr1_update(instr & 1);
}
void broadway::mtfsb1(ircolib::u32 instr) {
ircolib::u32 bit = 1 << utils::RD(instr);
ircolib::u32 mask = ~bit;
fpscr = (fpscr & mask) | bit;
cr1_update(instr & 1);
}
void broadway::mfmsr(ircolib::u32 instr) { gpr[utils::RS(instr)] = msr; }
void broadway::nand(ircolib::u32 instr) {
gpr[utils::RA(instr)] = ~(gpr[utils::RS(instr)] & gpr[utils::RB(instr)]);
cr0_update(instr & 1, gpr[utils::RA(instr)]);
}
void broadway::subf(ircolib::u32 instr) {
gpr[utils::RD(instr)] = ~(gpr[utils::RA(instr)] + gpr[utils::RB(instr)] + 1);
cr0_update(instr & 1, gpr[utils::RD(instr)]);
}
void broadway:: or (ircolib::u32 instr) {
gpr[utils::RA(instr)] = gpr[utils::RS(instr)] & gpr[utils::RB(instr)];
cr0_update(instr & 1, gpr[utils::RA(instr)]);
}
} // namespace weee::core
+29 -24
View File
@@ -7,6 +7,9 @@ namespace weee::core {
mem::mem() : vi(*this) {
mem1.resize(24_mib);
std::fill(mem1.begin(), mem1.end(), 0);
register_read8_handler(0x00000000, 0x017fffff, [&](ircolib::u32 addr) { return mem1[addr]; });
register_read16_handler(0x00000000, 0x017fffff,
[&](ircolib::u32 addr) { return ircolib::read_access<ircolib::u16>(mem1, addr); });
@@ -16,6 +19,8 @@ mem::mem() : vi(*this) {
register_read64_handler(0x00000000, 0x017fffff,
[&](ircolib::u32 addr) { return ircolib::read_access<ircolib::u64>(mem1, addr); });
register_write8_handler(0x00000000, 0x017fffff, [&](ircolib::u32 addr, ircolib::u8 value) { mem1[addr] = value; });
register_write16_handler(0x00000000, 0x017fffff, [&](ircolib::u32 addr, ircolib::u16 value) {
ircolib::write_access<ircolib::u16>(mem1, addr, value);
});
@@ -52,7 +57,7 @@ void mem::set(const ircolib::u8 val, const ircolib::u32 size, const ircolib::u32
memset(&mem1[offset], val, size);
}
ircolib::u8 mem::read8(ircolib::u32 addr) {
std::expected<ircolib::u8, std::string> mem::read8(ircolib::u32 addr) {
addr &= 0x0FFFFFFF;
for (const auto &handler : read8_handlers) {
if (ircolib::is_inside_range(addr, handler.start, handler.end)) {
@@ -60,11 +65,10 @@ ircolib::u8 mem::read8(ircolib::u32 addr) {
}
}
ircolib::panic("mem::read8 unimplemented addr 0x{:08X}", addr);
return 0;
return std::unexpected(std::format("mem::read8 unimplemented addr 0x{:08X}", addr));
}
ircolib::u16 mem::read16(ircolib::u32 addr) {
std::expected<ircolib::u16, std::string> mem::read16(ircolib::u32 addr) {
addr &= 0x0FFFFFFF;
for (const auto &handler : read16_handlers) {
if (ircolib::is_inside_range(addr, handler.start, handler.end)) {
@@ -72,11 +76,10 @@ ircolib::u16 mem::read16(ircolib::u32 addr) {
}
}
ircolib::panic("mem::read16 unimplemented addr 0x{:08X}", addr);
return 0;
return std::unexpected(std::format("mem::read16 unimplemented addr 0x{:08X}", addr));
}
ircolib::u32 mem::read32(ircolib::u32 addr) {
std::expected<ircolib::u32, std::string> mem::read32(ircolib::u32 addr) {
addr &= 0x0FFFFFFF;
for (const auto &handler : read32_handlers) {
if (ircolib::is_inside_range(addr, handler.start, handler.end)) {
@@ -84,11 +87,10 @@ ircolib::u32 mem::read32(ircolib::u32 addr) {
}
}
ircolib::panic("mem::read32 unimplemented addr 0x{:08X}", addr);
return 0;
return std::unexpected(std::format("mem::read32 unimplemented addr 0x{:08X}", addr));
}
ircolib::u64 mem::read64(ircolib::u32 addr) {
std::expected<ircolib::u64, std::string> mem::read64(ircolib::u32 addr) {
addr &= 0x0FFFFFFF;
for (const auto &handler : read64_handlers) {
if (ircolib::is_inside_range(addr, handler.start, handler.end)) {
@@ -96,51 +98,54 @@ ircolib::u64 mem::read64(ircolib::u32 addr) {
}
}
ircolib::panic("mem::read64 unimplemented addr 0x{:08X}", addr);
return 0;
return std::unexpected(std::format("mem::read64 unimplemented addr 0x{:08X}", addr));
}
void mem::write8(ircolib::u32 addr, ircolib::u8 value) {
std::expected<void, std::string> 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);
handler.func(addr - handler.start, value);
return std::expected<void, std::string>();
}
}
ircolib::panic("mem::write8 unimplemented addr 0x{:08X} = 0x{:02X}", addr, value);
return std::unexpected(std::format("mem::write8 unimplemented addr 0x{:08X} = 0x{:02X}", addr, value));
}
void mem::write16(ircolib::u32 addr, ircolib::u16 value) {
std::expected<void, std::string> 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);
handler.func(addr - handler.start, value);
return std::expected<void, std::string>();
}
}
ircolib::panic("mem::write16 unimplemented addr 0x{:08X} = 0x{:04X}", addr, value);
return std::unexpected(std::format("mem::write16 unimplemented addr 0x{:08X} = 0x{:04X}", addr, value));
}
void mem::write32(ircolib::u32 addr, ircolib::u32 value) {
std::expected<void, std::string> 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);
handler.func(addr - handler.start, value);
return std::expected<void, std::string>();
}
}
ircolib::panic("mem::write32 unimplemented addr 0x{:08X} = 0x{:08X}", addr, value);
return std::unexpected(std::format("mem::write32 unimplemented addr 0x{:08X} = 0x{:08X}", addr, value));
}
void mem::write64(ircolib::u32 addr, ircolib::u64 value) {
std::expected<void, std::string> 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);
handler.func(addr - handler.start, value);
return std::expected<void, std::string>();
}
}
ircolib::panic("mem::write64 unimplemented addr 0x{:08X} = 0x{:016X}", addr, value);
return std::unexpected(std::format("mem::write64 unimplemented addr 0x{:08X} = 0x{:016X}", addr, value));
}
} // namespace weee::core
+10 -8
View File
@@ -1,8 +1,10 @@
#pragma once
#include <string>
#include <vector>
#include <ircolib/types.hpp>
#include <broadway/mmio/vi.hpp>
#include <functional>
#include <expected>
namespace weee::core {
template <typename T>
@@ -53,14 +55,14 @@ struct mem {
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);
std::expected<ircolib::u8, std::string> read8(ircolib::u32);
std::expected<ircolib::u16, std::string> read16(ircolib::u32);
std::expected<ircolib::u32, std::string> read32(ircolib::u32);
std::expected<ircolib::u64, std::string> read64(ircolib::u32);
std::expected<void, std::string> write8(ircolib::u32, ircolib::u8);
std::expected<void, std::string> write16(ircolib::u32, ircolib::u16);
std::expected<void, std::string> write32(ircolib::u32, ircolib::u32);
std::expected<void, std::string> write64(ircolib::u32, ircolib::u64);
void copy(std::vector<ircolib::u8> &src, const ircolib::u32 offset);
void copy(ircolib::u8 *src, const ircolib::u32 size, const ircolib::u32 offset);