194 lines
4.6 KiB
C++
194 lines
4.6 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) {
|
|
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<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;
|
|
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("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));
|
|
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
|