Files
2026-05-20 17:55:07 +02:00

286 lines
6.4 KiB
C++

#include <broadway/utils.hpp>
#include <mem.hpp>
#include <print>
#include <ircolib/log.hpp>
#include <ircolib/mem_access.hpp>
#include <array>
namespace weee::core {
broadway::broadway() {
if (cs_open(CS_ARCH_PPC, cs_mode(CS_MODE_BIG_ENDIAN | CS_MODE_32), &capstone) != CS_ERR_OK) {
std::println("warning: could not initialize capstone. Disassembly is disabled");
disasm_available = false;
}
}
void broadway::set_pc(ircolib::u32 value) { pc = value; }
void broadway::run(mem &mem) {
std::println("pc: 0x{:08X}", pc);
for (int i = 0; i < 1000000; i++) {
ircolib::u32 instr = fetch(mem);
execute(instr, mem);
}
}
ircolib::u32 broadway::fetch(mem &mem) {
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:
std::println("broadway unknown special3 {} (0x{:04X}) (pc 0x{:08X})", secondary, secondary, pc - 4);
std::println("disassembly:");
print_disasm(instr);
ircolib::panic("LR: 0x{:08X}", lr);
}
}
void broadway::decode_special2(ircolib::u32 instr, mem &mem) {
auto secondary = utils::secondary(instr);
switch (secondary) {
case 0x000:
cmp(instr);
break;
case 0x008:
subfc(instr);
break;
case 0x00A:
addc(instr);
break;
case 0x013:
mfcr(instr);
break;
case 0x017:
lwzx(instr, mem);
break;
case 0x01C:
and(instr);
break;
case 0x020:
cmpl(instr);
break;
case 0x028:
subf(instr);
break;
case 0x053:
mfmsr(instr);
break;
case 0x088:
subfe(instr);
break;
case 0x08A:
adde(instr);
break;
case 0x090:
mtcrf(instr);
break;
case 0x092:
mtmsr(instr);
break;
case 0x097:
stwx(instr, mem);
break;
case 0x0CA:
addze(instr);
break;
case 0x0D2:
ircolib::warn("broadway TODO mtsr (pc 0x{:08X})", pc - 4);
break;
case 0x0EB:
mullw(instr);
break;
case 0x117:
lhzx(instr, mem);
break;
case 0x173:
mftb(instr);
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;
case 0x1CB:
divwu(instr);
break;
case 0x256: // sync
break;
case 0x318:
sraw(instr);
break;
default:
std::println("broadway unknown special2 {} (0x{:04X}) (pc 0x{:08X})", secondary, secondary, pc - 4);
std::println("disassembly:");
print_disasm(instr);
ircolib::panic("LR: 0x{:08X}", lr);
}
}
void broadway::decode_special1(ircolib::u32 instr, mem &mem) {
switch (utils::secondary(instr)) {
case 0x10:
bclrx(instr);
break;
case 0x32:
rfi(instr);
break;
case 0x96: // isync
break;
default:
std::println("broadway unknown special1 {} (0x{:04X}) (pc 0x{:08X})", utils::secondary(instr),
utils::secondary(instr), pc - 4);
std::println("disassembly:");
print_disasm(instr);
ircolib::panic("LR: 0x{:08X}", lr);
}
}
void broadway::execute(ircolib::u32 instr, mem &mem) {
const auto primary = utils::primary(instr);
switch (primary) {
case 7:
mulli(instr);
break;
case 8:
subfic(instr);
break;
case 10:
cmpli(instr);
break;
case 11:
cmpi(instr);
break;
case 12:
addic(instr);
break;
case 13:
addicr(instr);
break;
case 14:
addi(instr);
break;
case 15:
addis(instr);
break;
case 16:
bcx(instr);
break;
case 18:
bx(instr);
break;
case 19:
decode_special1(instr, mem);
break;
case 20:
rlwimi(instr);
break;
case 21:
rlwinm(instr);
break;
case 24:
ori(instr);
break;
case 25:
oris(instr);
break;
case 26:
xori(instr);
break;
case 28:
andi(instr);
break;
case 29:
andis(instr);
break;
case 31:
decode_special2(instr, mem);
break;
case 32:
lwz(instr, mem);
break;
case 33:
lwzu(instr, mem);
break;
case 34:
lbz(instr, mem);
break;
case 36:
stw(instr, mem);
break;
case 37:
stwu(instr, mem);
break;
case 38:
stb(instr, mem);
break;
case 39:
stbu(instr, mem);
break;
case 40:
lhz(instr, mem);
break;
case 44:
sth(instr, mem);
break;
case 45:
sthu(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, primary);
std::println("disassembly:");
print_disasm(instr);
ircolib::panic("LR: 0x{:08X}", lr);
}
}
void broadway::print_disasm(ircolib::u32 instr) {
if (!disasm_available)
return;
cs_insn *insn;
auto instr_buff = ircolib::integral_to_slice(std::byteswap(instr));
ircolib::u32 count = cs_disasm(capstone, instr_buff.data(), instr_buff.size(), pc - 4, 1, &insn);
if (count <= 0)
return;
ircolib::u32 j;
for (j = 0; j < count; j++) {
std::println("\t0x{:x}:\t{}\t\t{}", insn[j].address, insn[j].mnemonic, insn[j].op_str);
}
cs_free(insn, count);
}
} // namespace weee::core