#include #include #include #include #include #include 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) { 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) .and_then([&](ircolib::u32 val) { return std::expected(val); }) .or_else([&](std::string e) { ircolib::panic("broadway read failed. Reason {} (pc: 0x{:08X})", e, pc); return std::expected(); }) .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(secondary), instr); break; case 0x1DC: nand(instr); break; case 0x10A: add(instr); break; case 0x256: // sync break; default: ircolib::panic("broadway unknown special2 {} (0x{:04X}) (pc 0x{:08X})", secondary, secondary, pc - 4); } } 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: ircolib::panic("broadway unknown special1 {} (0x{:04X}) (pc 0x{:08X})", utils::secondary(instr), utils::secondary(instr), pc - 4); } } void broadway::execute(ircolib::u32 instr, mem &mem) { switch (utils::primary(instr)) { case 10: cmpli(instr); break; case 11: cmpi(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 21: rlwinm(instr); break; case 24: ori(instr); break; case 25: oris(instr); break; case 28: andi(instr); break; case 31: decode_special2(instr, mem); break; case 32: lwz(instr, mem); break; case 33: lwzu(instr, mem); break; case 36: stw(instr, mem); break; 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:"); print_disasm(instr); ircolib::panic(""); } } void broadway::print_disasm(ircolib::u32 instr) { if (!disasm_available) return; cs_insn *insn; auto instr_buff = ircolib::integral_to_slice(std::byteswap(instr)); size_t count = cs_disasm(capstone, instr_buff.data(), instr_buff.size(), pc - 4, 1, &insn); if (count <= 0) return; size_t 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