Beginning work on disassembler functions.
Ideally, this would be automated, but it's easier to just do it manually.
This commit is contained in:
@@ -9,12 +9,168 @@
|
||||
|
||||
#include <xenia/cpu/ppc/instr.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "cpu/ppc/instr_tables.h"
|
||||
|
||||
|
||||
using namespace xe::cpu::ppc;
|
||||
|
||||
|
||||
void InstrDisasm::Init(std::string name, uint32_t flags) {
|
||||
operands.clear();
|
||||
special_registers.clear();
|
||||
|
||||
if (flags & InstrDisasm::kOE) {
|
||||
name += "o";
|
||||
special_registers.push_back((InstrRegister){
|
||||
InstrRegister::kXER, 0, InstrRegister::kReadWrite
|
||||
});
|
||||
}
|
||||
if (flags & InstrDisasm::kRc) {
|
||||
name += ".";
|
||||
special_registers.push_back((InstrRegister){
|
||||
InstrRegister::kCR, 0, InstrRegister::kWrite
|
||||
});
|
||||
}
|
||||
if (flags & InstrDisasm::kCA) {
|
||||
special_registers.push_back((InstrRegister){
|
||||
InstrRegister::kXER, 0, InstrRegister::kReadWrite
|
||||
});
|
||||
}
|
||||
XEIGNORE(xestrcpya(this->name, XECOUNT(this->name), name.c_str()));
|
||||
}
|
||||
|
||||
void InstrDisasm::AddRegOperand(
|
||||
InstrRegister::RegisterSet set, uint32_t ordinal,
|
||||
InstrRegister::Access access, std::string display) {
|
||||
InstrOperand o;
|
||||
o.type = InstrOperand::kRegister;
|
||||
o.reg = (InstrRegister){
|
||||
set, ordinal, access
|
||||
};
|
||||
if (!display.size()) {
|
||||
std::stringstream display_out;
|
||||
switch (set) {
|
||||
case InstrRegister::kXER:
|
||||
display_out << "XER";
|
||||
break;
|
||||
case InstrRegister::kLR:
|
||||
display_out << "LR";
|
||||
break;
|
||||
case InstrRegister::kCTR:
|
||||
display_out << "CTR";
|
||||
break;
|
||||
case InstrRegister::kCR:
|
||||
display_out << "CR";
|
||||
display_out << ordinal;
|
||||
break;
|
||||
case InstrRegister::kFPSCR:
|
||||
display_out << "FPSCR";
|
||||
break;
|
||||
case InstrRegister::kGPR:
|
||||
display_out << "r";
|
||||
display_out << ordinal;
|
||||
break;
|
||||
case InstrRegister::kFPR:
|
||||
display_out << "f";
|
||||
display_out << ordinal;
|
||||
break;
|
||||
case InstrRegister::kVMX:
|
||||
display_out << "v";
|
||||
display_out << ordinal;
|
||||
break;
|
||||
}
|
||||
display = display_out.str();
|
||||
}
|
||||
XEIGNORE(xestrcpya(o.display, XECOUNT(o.display), display.c_str()));
|
||||
operands.push_back(o);
|
||||
}
|
||||
|
||||
void InstrDisasm::AddSImmOperand(uint64_t value, size_t width,
|
||||
std::string display) {
|
||||
InstrOperand o;
|
||||
o.type = InstrOperand::kImmediate;
|
||||
o.imm.is_signed = true;
|
||||
o.imm.value = value;
|
||||
o.imm.width = value;
|
||||
if (display.size()) {
|
||||
XEIGNORE(xestrcpya(o.display, XECOUNT(o.display), display.c_str()));
|
||||
} else {
|
||||
const size_t max_count = XECOUNT(o.display);
|
||||
switch (width) {
|
||||
case 1:
|
||||
xesnprintfa(o.display, max_count, "%d", (int32_t)(int8_t)value);
|
||||
break;
|
||||
case 2:
|
||||
xesnprintfa(o.display, max_count, "%d", (int32_t)(int16_t)value);
|
||||
break;
|
||||
case 4:
|
||||
xesnprintfa(o.display, max_count, "%d", (int32_t)value);
|
||||
break;
|
||||
case 8:
|
||||
xesnprintfa(o.display, max_count, "%lld", (int64_t)value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
operands.push_back(o);
|
||||
}
|
||||
|
||||
void InstrDisasm::AddUImmOperand(uint64_t value, size_t width,
|
||||
std::string display) {
|
||||
InstrOperand o;
|
||||
o.type = InstrOperand::kImmediate;
|
||||
o.imm.is_signed = false;
|
||||
o.imm.value = value;
|
||||
o.imm.width = value;
|
||||
if (display.size()) {
|
||||
XEIGNORE(xestrcpya(o.display, XECOUNT(o.display), display.c_str()));
|
||||
} else {
|
||||
const size_t max_count = XECOUNT(o.display);
|
||||
switch (width) {
|
||||
case 1:
|
||||
xesnprintfa(o.display, max_count, "%.2X", (uint8_t)value);
|
||||
break;
|
||||
case 2:
|
||||
xesnprintfa(o.display, max_count, "%.4X", (uint16_t)value);
|
||||
break;
|
||||
case 4:
|
||||
xesnprintfa(o.display, max_count, "%.8X", (uint32_t)value);
|
||||
break;
|
||||
case 8:
|
||||
xesnprintfa(o.display, max_count, "%.16llX", value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
operands.push_back(o);
|
||||
}
|
||||
|
||||
int InstrDisasm::Finish() {
|
||||
// TODO(benvanik): setup fast checks
|
||||
reg_mask = 0;
|
||||
gpr_mask = 0;
|
||||
fpr_mask = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void InstrDisasm::Dump(std::string& str, size_t pad) {
|
||||
str = name;
|
||||
if (operands.size()) {
|
||||
if (pad && str.size() < pad) {
|
||||
str += std::string(pad - str.size(), ' ');
|
||||
}
|
||||
for (std::vector<InstrOperand>::iterator it = operands.begin();
|
||||
it != operands.end(); ++it) {
|
||||
str += it->display;
|
||||
|
||||
if (it + 1 != operands.end()) {
|
||||
str += ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InstrType* xe::cpu::ppc::GetInstrType(uint32_t code) {
|
||||
InstrType* slot = NULL;
|
||||
switch (code >> 26) {
|
||||
@@ -60,7 +216,19 @@ InstrType* xe::cpu::ppc::GetInstrType(uint32_t code) {
|
||||
return slot;
|
||||
}
|
||||
|
||||
int xe::cpu::ppc::RegisterInstrEmit(uint32_t code, void* emit) {
|
||||
int xe::cpu::ppc::RegisterInstrDisassemble(
|
||||
uint32_t code, InstrDisassembleFn disassemble) {
|
||||
InstrType* instr_type = GetInstrType(code);
|
||||
XEASSERTNOTNULL(instr_type);
|
||||
if (!instr_type) {
|
||||
return 1;
|
||||
}
|
||||
XEASSERTNULL(instr_type->disassemble);
|
||||
instr_type->disassemble = disassemble;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xe::cpu::ppc::RegisterInstrEmit(uint32_t code, InstrEmitFn emit) {
|
||||
InstrType* instr_type = GetInstrType(code);
|
||||
XEASSERTNOTNULL(instr_type);
|
||||
if (!instr_type) {
|
||||
|
||||
Reference in New Issue
Block a user