Probably buggy SNES disassembler
This commit is contained in:
parent
6ce7b3dc7b
commit
08e5f6acc9
12 changed files with 726 additions and 48 deletions
22
include/interface/disassembler.hpp
Normal file
22
include/interface/disassembler.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef _interface__disassembler__hpp__included__
|
||||||
|
#define _interface__disassembler__hpp__included__
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
class disassembler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
disassembler(const std::string& name);
|
||||||
|
virtual ~disassembler();
|
||||||
|
virtual std::string disassemble(uint64_t base, std::function<unsigned char()> fetchpc) = 0;
|
||||||
|
static disassembler& byname(const std::string& name);
|
||||||
|
template<typename T> static T fetch_le(std::function<unsigned char()> fetchpc);
|
||||||
|
template<typename T> static T fetch_be(std::function<unsigned char()> fetchpc);
|
||||||
|
private:
|
||||||
|
std::string name;
|
||||||
|
static std::map<std::string, disassembler*>& disasms();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -17,6 +17,17 @@ struct core_romimage;
|
||||||
struct core_romimage_info;
|
struct core_romimage_info;
|
||||||
struct core_core;
|
struct core_core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface device register.
|
||||||
|
*/
|
||||||
|
struct interface_device_reg
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
uint64_t (*read)();
|
||||||
|
void (*write)(uint64_t v);
|
||||||
|
bool boolean;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An parameter for action in interface.
|
* An parameter for action in interface.
|
||||||
*/
|
*/
|
||||||
|
@ -371,6 +382,10 @@ struct core_core_params
|
||||||
* Execute action.
|
* Execute action.
|
||||||
*/
|
*/
|
||||||
void (*execute_action)(unsigned id, const std::vector<interface_action_paramval>& p);
|
void (*execute_action)(unsigned id, const std::vector<interface_action_paramval>& p);
|
||||||
|
/**
|
||||||
|
* Get set of interface device registers.
|
||||||
|
*/
|
||||||
|
const struct interface_device_reg* (*get_registers)();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct core_region
|
struct core_region
|
||||||
|
@ -469,6 +484,7 @@ struct core_core
|
||||||
void do_unregister_action(const std::string& key);
|
void do_unregister_action(const std::string& key);
|
||||||
std::set<const interface_action*> get_actions();
|
std::set<const interface_action*> get_actions();
|
||||||
_param_register_proxy param_register_proxy;
|
_param_register_proxy param_register_proxy;
|
||||||
|
const interface_device_reg* get_registers();
|
||||||
private:
|
private:
|
||||||
std::string (*_core_identifier)();
|
std::string (*_core_identifier)();
|
||||||
bool (*_set_region)(core_region& region);
|
bool (*_set_region)(core_region& region);
|
||||||
|
@ -494,6 +510,7 @@ private:
|
||||||
std::string (*_get_core_shortname)();
|
std::string (*_get_core_shortname)();
|
||||||
void (*_pre_emulate_frame)(controller_frame& cf);
|
void (*_pre_emulate_frame)(controller_frame& cf);
|
||||||
void (*_execute_action)(unsigned id, const std::vector<interface_action_paramval>& p);
|
void (*_execute_action)(unsigned id, const std::vector<interface_action_paramval>& p);
|
||||||
|
const interface_device_reg* (*_get_registers)();
|
||||||
bool hidden;
|
bool hidden;
|
||||||
std::map<std::string, interface_action*> actions;
|
std::map<std::string, interface_action*> actions;
|
||||||
mutex_class actions_lock;
|
mutex_class actions_lock;
|
||||||
|
@ -561,6 +578,7 @@ public:
|
||||||
bool is_hidden() { return core->is_hidden(); }
|
bool is_hidden() { return core->is_hidden(); }
|
||||||
void pre_emulate_frame(controller_frame& cf) { return core->pre_emulate_frame(cf); }
|
void pre_emulate_frame(controller_frame& cf) { return core->pre_emulate_frame(cf); }
|
||||||
std::set<const interface_action*> get_actions() { return core->get_actions(); }
|
std::set<const interface_action*> get_actions() { return core->get_actions(); }
|
||||||
|
const interface_device_reg* get_registers() { return core->get_registers(); }
|
||||||
private:
|
private:
|
||||||
core_type(const core_type&);
|
core_type(const core_type&);
|
||||||
core_type& operator=(const core_type&);
|
core_type& operator=(const core_type&);
|
||||||
|
|
119
src/core/disassemble.cpp
Normal file
119
src/core/disassemble.cpp
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#include "core/command.hpp"
|
||||||
|
#include "interface/disassembler.hpp"
|
||||||
|
#include "library/bintohex.hpp"
|
||||||
|
#include "library/minmax.hpp"
|
||||||
|
#include "core/memorymanip.hpp"
|
||||||
|
#include "core/window.hpp"
|
||||||
|
#include "library/string.hpp"
|
||||||
|
#include <iomanip>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct dres
|
||||||
|
{
|
||||||
|
uint64_t addr;
|
||||||
|
uint64_t len;
|
||||||
|
std::string disasm;
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned char hex(char ch)
|
||||||
|
{
|
||||||
|
switch(ch) {
|
||||||
|
case '0': return 0;
|
||||||
|
case '1': return 1;
|
||||||
|
case '2': return 2;
|
||||||
|
case '3': return 3;
|
||||||
|
case '4': return 4;
|
||||||
|
case '5': return 5;
|
||||||
|
case '6': return 6;
|
||||||
|
case '7': return 7;
|
||||||
|
case '8': return 8;
|
||||||
|
case '9': return 9;
|
||||||
|
case 'a': case 'A': return 10;
|
||||||
|
case 'b': case 'B': return 11;
|
||||||
|
case 'c': case 'C': return 12;
|
||||||
|
case 'd': case 'D': return 13;
|
||||||
|
case 'e': case 'E': return 14;
|
||||||
|
case 'f': case 'F': return 15;
|
||||||
|
};
|
||||||
|
throw std::runtime_error("Bad hex character");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t parse_hexordec(const std::string& k)
|
||||||
|
{
|
||||||
|
regex_results t;
|
||||||
|
uint64_t address = 0;
|
||||||
|
if(t = regex("0x(.+)", k)) {
|
||||||
|
if(t[1].length() > 16)
|
||||||
|
throw 42;
|
||||||
|
address = 0;
|
||||||
|
for(unsigned i = 0; i < t[1].length(); i++)
|
||||||
|
address = 16 * address + hex(t[1][i]);
|
||||||
|
} else {
|
||||||
|
address = parse_value<uint64_t>(k);
|
||||||
|
}
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
function_ptr_command<const std::string&> disassemble(lsnes_cmd, "disassemble", "Disassemble code",
|
||||||
|
"Syntax: disassemble <kind> <addr> [<count>] [to <filename>]\nDisassemble code\n",
|
||||||
|
[](const std::string& t) throw(std::bad_alloc, std::runtime_error) {
|
||||||
|
regex_results r = regex("([^ \t]+)[ \t]+([0-9]+|0x[0-9A-Fa-f]+)([ \t]+([0-9]+))?"
|
||||||
|
"([ \t]+to[ \t]+(.+))?", t);
|
||||||
|
if(!r) {
|
||||||
|
messages << "Syntax: disassemble <kind> <addr> [<count>] [to <filename>]" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::string kind = r[1];
|
||||||
|
uint64_t addr = parse_hexordec(r[2]);
|
||||||
|
uint64_t count = 1;
|
||||||
|
if(r[4] != "")
|
||||||
|
count = parse_value<uint64_t>(r[4]);
|
||||||
|
std::string file;
|
||||||
|
if(r[6] != "")
|
||||||
|
file = r[6];
|
||||||
|
std::list<dres> result;
|
||||||
|
disassembler* d;
|
||||||
|
try {
|
||||||
|
d = &disassembler::byname(kind);
|
||||||
|
} catch(std::exception& e) {
|
||||||
|
messages << "Can't find such disassembler" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint64_t laddr = addr;
|
||||||
|
uint64_t longest = 0;
|
||||||
|
for(uint64_t i = 1; i <= count; i++) {
|
||||||
|
uint64_t bytes = 0;
|
||||||
|
dres x;
|
||||||
|
x.addr = laddr;
|
||||||
|
x.disasm = d->disassemble(laddr, [&bytes, laddr]() -> unsigned char {
|
||||||
|
return lsnes_memory.read<uint8_t>(laddr + bytes++);
|
||||||
|
});
|
||||||
|
x.len = bytes;
|
||||||
|
result.push_back(x);
|
||||||
|
longest = max(longest, bytes);
|
||||||
|
laddr += bytes;
|
||||||
|
}
|
||||||
|
std::ostream* strm = &messages.getstream();
|
||||||
|
if(file != "") {
|
||||||
|
strm = new std::ofstream(file);
|
||||||
|
if(!*strm) {
|
||||||
|
messages << "Can't open output file" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(auto i : result) {
|
||||||
|
std::vector<unsigned char> tmp;
|
||||||
|
tmp.resize(i.len);
|
||||||
|
lsnes_memory.read_range(i.addr, &tmp[0], i.len);
|
||||||
|
std::string l = (stringfmt() << std::setw(16) << std::setfill('0') << std::hex
|
||||||
|
<< i.addr).str() + " " + binary_to_hex(&tmp[0], i.len) + " "
|
||||||
|
+ i.disasm;
|
||||||
|
(*strm) << l << std::endl;
|
||||||
|
}
|
||||||
|
if(file != "")
|
||||||
|
delete strm;
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
ifdef BSNES_VERSION
|
ifdef BSNES_VERSION
|
||||||
OBJECTS=core.$(OBJECT_SUFFIX)
|
OBJECTS=core.$(OBJECT_SUFFIX) scpu-disasm.$(OBJECT_SUFFIX)
|
||||||
BSNES_CFLAGS=
|
BSNES_CFLAGS=
|
||||||
BSNES_LDFLAGS=
|
BSNES_LDFLAGS=
|
||||||
ifdef BSNES_IS_COMPAT
|
ifdef BSNES_IS_COMPAT
|
||||||
|
|
|
@ -94,6 +94,56 @@ namespace
|
||||||
0, 0 //Offset.
|
0, 0 //Offset.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct interface_device_reg snes_registers[] = {
|
||||||
|
{"pbpc", []() -> uint64_t { return SNES::cpu.regs.pc; }, [](uint64_t v) { SNES::cpu.regs.pc = v; }},
|
||||||
|
{"pb", []() -> uint64_t { return SNES::cpu.regs.pc >> 16; },
|
||||||
|
[](uint64_t v) { SNES::cpu.regs.pc = (v << 16) | (SNES::cpu.regs.pc & 0xFFFF); }},
|
||||||
|
{"pc", []() -> uint64_t { return SNES::cpu.regs.pc & 0xFFFF; },
|
||||||
|
[](uint64_t v) { SNES::cpu.regs.pc = (v & 0xFFFF) | (SNES::cpu.regs.pc & ~0xFFFF); }},
|
||||||
|
{"r0", []() -> uint64_t { return SNES::cpu.regs.r[0]; }, [](uint64_t v) { SNES::cpu.regs.r[0] = v; }},
|
||||||
|
{"r1", []() -> uint64_t { return SNES::cpu.regs.r[1]; }, [](uint64_t v) { SNES::cpu.regs.r[1] = v; }},
|
||||||
|
{"r2", []() -> uint64_t { return SNES::cpu.regs.r[2]; }, [](uint64_t v) { SNES::cpu.regs.r[2] = v; }},
|
||||||
|
{"r3", []() -> uint64_t { return SNES::cpu.regs.r[3]; }, [](uint64_t v) { SNES::cpu.regs.r[3] = v; }},
|
||||||
|
{"r4", []() -> uint64_t { return SNES::cpu.regs.r[4]; }, [](uint64_t v) { SNES::cpu.regs.r[4] = v; }},
|
||||||
|
{"r5", []() -> uint64_t { return SNES::cpu.regs.r[5]; }, [](uint64_t v) { SNES::cpu.regs.r[5] = v; }},
|
||||||
|
{"a", []() -> uint64_t { return SNES::cpu.regs.a; }, [](uint64_t v) { SNES::cpu.regs.a = v; }},
|
||||||
|
{"x", []() -> uint64_t { return SNES::cpu.regs.x; }, [](uint64_t v) { SNES::cpu.regs.x = v; }},
|
||||||
|
{"y", []() -> uint64_t { return SNES::cpu.regs.y; }, [](uint64_t v) { SNES::cpu.regs.y = v; }},
|
||||||
|
{"z", []() -> uint64_t { return SNES::cpu.regs.z; }, [](uint64_t v) { SNES::cpu.regs.z = v; }},
|
||||||
|
{"s", []() -> uint64_t { return SNES::cpu.regs.s; }, [](uint64_t v) { SNES::cpu.regs.s = v; }},
|
||||||
|
{"d", []() -> uint64_t { return SNES::cpu.regs.d; }, [](uint64_t v) { SNES::cpu.regs.d = v; }},
|
||||||
|
{"db", []() -> uint64_t { return SNES::cpu.regs.db; }, [](uint64_t v) { SNES::cpu.regs.db = v; }},
|
||||||
|
{"p", []() -> uint64_t { return SNES::cpu.regs.p; }, [](uint64_t v) { SNES::cpu.regs.p = v; }},
|
||||||
|
{"e", []() -> uint64_t { return SNES::cpu.regs.e; }, [](uint64_t v) { SNES::cpu.regs.e = v; }},
|
||||||
|
{"irq", []() -> uint64_t { return SNES::cpu.regs.irq; }, [](uint64_t v) { SNES::cpu.regs.irq = v; }},
|
||||||
|
{"wai", []() -> uint64_t { return SNES::cpu.regs.wai; }, [](uint64_t v) { SNES::cpu.regs.wai = v; }},
|
||||||
|
{"mdr", []() -> uint64_t { return SNES::cpu.regs.mdr; }, [](uint64_t v) { SNES::cpu.regs.mdr = v; }},
|
||||||
|
{"vector", []() -> uint64_t { return SNES::cpu.regs.vector; },
|
||||||
|
[](uint64_t v) { SNES::cpu.regs.vector = v; }},
|
||||||
|
{"aa", []() -> uint64_t { return SNES::cpu.aa; }, [](uint64_t v) { SNES::cpu.aa = v; }},
|
||||||
|
{"rd", []() -> uint64_t { return SNES::cpu.rd; }, [](uint64_t v) { SNES::cpu.rd = v; }},
|
||||||
|
{"sp", []() -> uint64_t { return SNES::cpu.sp; }, [](uint64_t v) { SNES::cpu.sp = v; }},
|
||||||
|
{"dp", []() -> uint64_t { return SNES::cpu.dp; }, [](uint64_t v) { SNES::cpu.dp = v; }},
|
||||||
|
{"p_n", []() -> uint64_t { return SNES::cpu.regs.p.n; }, [](uint64_t v) { SNES::cpu.regs.p.n = v; },
|
||||||
|
true},
|
||||||
|
{"p_v", []() -> uint64_t { return SNES::cpu.regs.p.v; }, [](uint64_t v) { SNES::cpu.regs.p.v = v; },
|
||||||
|
true},
|
||||||
|
{"p_m", []() -> uint64_t { return SNES::cpu.regs.p.m; }, [](uint64_t v) { SNES::cpu.regs.p.m = v; },
|
||||||
|
true},
|
||||||
|
{"p_x", []() -> uint64_t { return SNES::cpu.regs.p.x; }, [](uint64_t v) { SNES::cpu.regs.p.x = v; },
|
||||||
|
true},
|
||||||
|
{"p_d", []() -> uint64_t { return SNES::cpu.regs.p.d; }, [](uint64_t v) { SNES::cpu.regs.p.d = v; },
|
||||||
|
true},
|
||||||
|
{"p_i", []() -> uint64_t { return SNES::cpu.regs.p.i; }, [](uint64_t v) { SNES::cpu.regs.p.i = v; },
|
||||||
|
true},
|
||||||
|
{"p_z", []() -> uint64_t { return SNES::cpu.regs.p.z; }, [](uint64_t v) { SNES::cpu.regs.p.z = v; },
|
||||||
|
true},
|
||||||
|
{"p_c", []() -> uint64_t { return SNES::cpu.regs.p.c; }, [](uint64_t v) { SNES::cpu.regs.p.c = v; },
|
||||||
|
true},
|
||||||
|
//TODO: SMP registers, DSP registers, chip registers.
|
||||||
|
{NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
#include "ports.inc"
|
#include "ports.inc"
|
||||||
#include "slots.inc"
|
#include "slots.inc"
|
||||||
#include "regions.inc"
|
#include "regions.inc"
|
||||||
|
@ -867,7 +917,8 @@ again2:
|
||||||
do_hreset_flag = true;
|
do_hreset_flag = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
.get_registers = []() -> const interface_device_reg* { return snes_registers; },
|
||||||
}};
|
}};
|
||||||
|
|
||||||
core_type type_snes{{
|
core_type type_snes{{
|
||||||
|
@ -937,49 +988,6 @@ again2:
|
||||||
x.write(&out[0], out.size());
|
x.write(&out[0], out.size());
|
||||||
});
|
});
|
||||||
|
|
||||||
function_ptr_luafun lua_memory_readreg(LS, "memory.getregister", [](lua_state& L, const std::string& fname) ->
|
|
||||||
int {
|
|
||||||
std::string r = L.get_string(1, fname.c_str());
|
|
||||||
auto& c = SNES::cpu.regs;
|
|
||||||
auto& c2 = SNES::cpu;
|
|
||||||
if(r == "pbpc") L.pushnumber((unsigned)c.pc);
|
|
||||||
else if(r == "pb") L.pushnumber((unsigned)c.pc >> 16);
|
|
||||||
else if(r == "pc") L.pushnumber((unsigned)c.pc & 0xFFFF);
|
|
||||||
else if(r == "r0") L.pushnumber((unsigned)c.r[0]);
|
|
||||||
else if(r == "r1") L.pushnumber((unsigned)c.r[1]);
|
|
||||||
else if(r == "r2") L.pushnumber((unsigned)c.r[2]);
|
|
||||||
else if(r == "r3") L.pushnumber((unsigned)c.r[3]);
|
|
||||||
else if(r == "r4") L.pushnumber((unsigned)c.r[4]);
|
|
||||||
else if(r == "r5") L.pushnumber((unsigned)c.r[5]);
|
|
||||||
else if(r == "a") L.pushnumber((unsigned)c.a);
|
|
||||||
else if(r == "x") L.pushnumber((unsigned)c.x);
|
|
||||||
else if(r == "y") L.pushnumber((unsigned)c.y);
|
|
||||||
else if(r == "z") L.pushnumber((unsigned)c.z);
|
|
||||||
else if(r == "s") L.pushnumber((unsigned)c.s);
|
|
||||||
else if(r == "d") L.pushnumber((unsigned)c.d);
|
|
||||||
else if(r == "db") L.pushnumber((unsigned)c.db);
|
|
||||||
else if(r == "p") L.pushnumber((unsigned)c.p);
|
|
||||||
else if(r == "p_n") L.pushboolean(c.p.n);
|
|
||||||
else if(r == "p_v") L.pushboolean(c.p.v);
|
|
||||||
else if(r == "p_m") L.pushboolean(c.p.m);
|
|
||||||
else if(r == "p_x") L.pushboolean(c.p.x);
|
|
||||||
else if(r == "p_d") L.pushboolean(c.p.d);
|
|
||||||
else if(r == "p_i") L.pushboolean(c.p.i);
|
|
||||||
else if(r == "p_z") L.pushboolean(c.p.z);
|
|
||||||
else if(r == "p_c") L.pushboolean(c.p.c);
|
|
||||||
else if(r == "e") L.pushboolean(c.e);
|
|
||||||
else if(r == "irq") L.pushboolean(c.irq);
|
|
||||||
else if(r == "wai") L.pushboolean(c.wai);
|
|
||||||
else if(r == "mdr") L.pushnumber((unsigned)c.mdr);
|
|
||||||
else if(r == "vector") L.pushnumber((unsigned)c.vector);
|
|
||||||
else if(r == "aa") L.pushnumber((unsigned)c2.aa);
|
|
||||||
else if(r == "rd") L.pushnumber((unsigned)c2.rd);
|
|
||||||
else if(r == "sp") L.pushnumber((unsigned)c2.sp);
|
|
||||||
else if(r == "dp") L.pushnumber((unsigned)c2.dp);
|
|
||||||
else L.pushnil();
|
|
||||||
return 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
#ifdef BSNES_HAS_DEBUGGER
|
#ifdef BSNES_HAS_DEBUGGER
|
||||||
char snes_debug_cb_keys[SNES::Debugger::Breakpoints];
|
char snes_debug_cb_keys[SNES::Debugger::Breakpoints];
|
||||||
char snes_debug_cb_trace;
|
char snes_debug_cb_trace;
|
||||||
|
|
279
src/emulation/bsnes-legacy/scpu-disasm.cpp
Normal file
279
src/emulation/bsnes-legacy/scpu-disasm.cpp
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
#include "interface/disassembler.hpp"
|
||||||
|
#include "library/string.hpp"
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::string tohex(uint8_t x)
|
||||||
|
{
|
||||||
|
return (stringfmt() << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(x)).str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string tohex(uint16_t x)
|
||||||
|
{
|
||||||
|
return (stringfmt() << std::setw(4) << std::setfill('0') << std::hex << x).str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool k> struct varsize {};
|
||||||
|
template<> struct varsize<false> { typedef uint8_t type_t; };
|
||||||
|
template<> struct varsize<true> { typedef uint16_t type_t; };
|
||||||
|
|
||||||
|
template<bool laddr, bool lacc> struct scpu_disassembler : public disassembler
|
||||||
|
{
|
||||||
|
scpu_disassembler(const std::string& n) : disassembler(n) {}
|
||||||
|
std::string disassemble(uint64_t base, std::function<unsigned char()> fetchpc);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ssmp_disassembler : public disassembler
|
||||||
|
{
|
||||||
|
ssmp_disassembler(const std::string& n) : disassembler(n) {}
|
||||||
|
std::string disassemble(uint64_t base, std::function<unsigned char()> fetchpc);
|
||||||
|
};
|
||||||
|
|
||||||
|
scpu_disassembler<false, false> d1("snes-xa");
|
||||||
|
scpu_disassembler<false, true> d2("snes-xA");
|
||||||
|
scpu_disassembler<true, false> d3("snes-Xa");
|
||||||
|
scpu_disassembler<true, true> d4("snes-XA");
|
||||||
|
ssmp_disassembler d5("snes-smp");
|
||||||
|
|
||||||
|
//%0: Byte-sized quantity, loaded before %b.
|
||||||
|
//%a: Accumulator-sized quantity.
|
||||||
|
//%b: Byte-sized quantity.
|
||||||
|
//%l: Long address.
|
||||||
|
//%r: Byte relative.
|
||||||
|
//%R: Word relative.
|
||||||
|
//%w: Word-sized quantity.
|
||||||
|
//%x: Index-sizeed quantity.
|
||||||
|
const char* scpu_instructions[] = {
|
||||||
|
"brk #%b", "ora (%b,x)", "cop #%b", "ora %b,s", //00
|
||||||
|
"tsb %b", "ora %b", "asl %b", "ora [%b]", //04
|
||||||
|
"php", "ora #%a", "asl a", "phd", //08
|
||||||
|
"tsb %w", "ora %w", "asl %w", "ora %l", //0C
|
||||||
|
"bpl %r", "ora (%b),y", "ora (%b)", "ora (%b,s),y", //10
|
||||||
|
"trb %b", "ora %b,x", "asl %b,x", "ora [%b],y", //14
|
||||||
|
"clc", "ora %w,y", "inc", "tcs", //18
|
||||||
|
"trb %w", "ora %w,x", "asl %w,x", "ora %l,x", //1C
|
||||||
|
"jsr %w", "and (%b,x)", "jsl %l", "and %b,s", //20
|
||||||
|
"bit %b", "and %b", "rol %b", "and [%b]", //24
|
||||||
|
"plp", "and #%a", "rol a", "pld", //28
|
||||||
|
"bit %w", "and %w", "rol %w", "and %l", //2C
|
||||||
|
"bmi %r", "and (%b),y", "and (%b)", "and (%b,s),y", //30
|
||||||
|
"bit %b", "and %b,x", "rol %b,x", "and [%b],y", //34
|
||||||
|
"sec", "and %w,y", "dec", "tsc", //38
|
||||||
|
"bit %w,x", "and %w,x", "rol %w,x", "and %l,x", //3C
|
||||||
|
"rti", "eor (%b,x)", "wdm #%b", "eor %b,s", //40
|
||||||
|
"mvp %b,%0", "eor %b", "lsr %b", "eor [%b]", //44
|
||||||
|
"pha", "eor #%a", "lsr a", "phk", //48
|
||||||
|
"jmp %w", "eor %w", "lsr %w", "eor %l", //4C
|
||||||
|
"bvc %r", "eor (%b),y", "eor (%b)", "eor (%b,s),y", //50
|
||||||
|
"mnv %b,%0", "eor %b,x", "lsr %b,x", "eor [%b],y", //54
|
||||||
|
"cli", "eor %w,y", "phy", "tcd", //58
|
||||||
|
"jml %l", "eor %w,x", "lsr %w,x", "eor %l,x", //5C
|
||||||
|
"rts", "adc (%b,x)", "per %w", "adc %b,s", //60
|
||||||
|
"stz %b", "adc %b", "ror %b", "adc [%b]", //64
|
||||||
|
"pla", "adc #%a", "ror a", "rtl", //68
|
||||||
|
"jmp (%w)", "adc %w", "ror %w", "adc %l", //6C
|
||||||
|
"bvs %r", "adc (%b),y", "adc (%b)", "adc (%b,s),y", //70
|
||||||
|
"stz %b,x", "adc %b,x", "ror %b,x", "adc [%b],y", //74
|
||||||
|
"sei", "adc %w,y", "ply", "tdc", //78
|
||||||
|
"jmp (%w,x)", "adc %w,x", "ror %w,x", "adc %l,x", //7C
|
||||||
|
"bra %r", "sta (%b,x)", "brl %R", "sta %b,s", //80
|
||||||
|
"sty %b", "sta %b", "stx %b", "sta [%b]", //84
|
||||||
|
"dey", "bit #%a", "txa", "phb", //88
|
||||||
|
"sty %w", "sta %w", "stx %w", "sta %l", //8C
|
||||||
|
"bcc %r", "sta (%b),y", "sta (%b)", "sta (%b,s),y", //90
|
||||||
|
"sty %b,x", "sta %b,x", "stx %b,y", "sta [%b],y", //94
|
||||||
|
"tya", "sta %w,y", "txs", "txy", //98
|
||||||
|
"stz %w", "sta %w,x", "stz %w,x", "sta %l,x", //9C
|
||||||
|
"ldy #%x", "lda (%b,x)", "ldx #%x", "lda %b,s", //A0
|
||||||
|
"ldy %b", "lda %b", "ldx %b", "lda [%b]", //A4
|
||||||
|
"tay", "lda #%a", "tax", "plb", //A8
|
||||||
|
"ldy %w", "lda %w", "ldx %w", "lda %l", //AC
|
||||||
|
"bcs %r", "lda (%b),y", "lda (%b)", "lda (%b,s),y", //B0
|
||||||
|
"ldy %b,x", "lda %b,x", "ldx %b,y", "lda [%b],y", //B4
|
||||||
|
"clv", "lda %w,y", "tsx", "tyx", //B8
|
||||||
|
"ldy %w,x", "lda %w,x", "ldx %w,x", "lda %l,x", //BC
|
||||||
|
"cpy #%x", "cmp (%b,x)", "rep #%b", "cmp %b,s", //C0
|
||||||
|
"cpy %b", "cmp %b", "dec %b", "cmp [%b]", //C4
|
||||||
|
"iny", "cmp #%a", "dex", "wai", //C8
|
||||||
|
"cpy %w", "cmp %w", "dec %w", "cmp %l", //CC
|
||||||
|
"bne %r", "cmp (%b),y", "cmp (%b)", "cmp (%b,s),y", //D0
|
||||||
|
"pei (%b)", "cmp %b,x", "dec %b,y", "cmp [%b],y", //D4
|
||||||
|
"cld", "cmp %w,y", "phx", "stp", //D8
|
||||||
|
"jmp [%w]", "cmp %w,x", "dec %w,x", "cmp %l,x", //DC
|
||||||
|
"cpx #%x", "sbc (%b,x)", "sep #%b", "sbc %b,s", //E0
|
||||||
|
"cpx %b", "sbc %b", "inc %b", "sbc [%b]", //E4
|
||||||
|
"inx", "sbc #%a", "nop", "xba", //E8
|
||||||
|
"cpx %w", "sbc %w", "inc %w", "sbc %l", //EC
|
||||||
|
"beq %r", "sbc (%b),y", "sbc (%b)", "sbc (%b,s),y", //F0
|
||||||
|
"pea %w", "sbc %b,x", "inc %b,y", "sbc [%b],y", //F4
|
||||||
|
"sed", "sbc %w,y", "plx", "xce", //F8
|
||||||
|
"jsr (%w,x)", "sbc %w,x", "inc %w,x", "sbc %l,x" //FC
|
||||||
|
};
|
||||||
|
|
||||||
|
//%0: Byte-sized quantity, loaded before %b.
|
||||||
|
//%b: Byte-sized quantity.
|
||||||
|
//%c: ??? <n>:<m> construct.
|
||||||
|
//%r: Relative
|
||||||
|
//%R: Relative
|
||||||
|
//%w: Word-sized quantity.
|
||||||
|
const char* ssmp_instructions[] = {
|
||||||
|
"nop", "jst $ffde", "set %b:0", "bbs %b:0=%R", //00
|
||||||
|
"ora %b", "ora %w", "ora (x)", "ora (%b,x)", //04
|
||||||
|
"ora #%b", "orr %b=%0", "orc %c", "asl %b", //08
|
||||||
|
"asl %w", "php", "tsb %w", "brk", //0C
|
||||||
|
"bpl %r", "jst $ffdc", "clr %b:0", "bbc %b:0=%R", //10
|
||||||
|
"ora %b,x", "ora %w,x", "ora %w,y", "ora (%b),y", //14
|
||||||
|
"orr %b=#%0", "orr (x)=(y)", "dew %b", "asl %b,x", //18
|
||||||
|
"asl", "dex", "cpx %w", "jmp (%w,x)", //1C
|
||||||
|
"clp", "jst $ffda", "set %b:1", "bbs %b:1=%R", //20
|
||||||
|
"and %b", "and %w", "and (x)", "and (%b,x)", //24
|
||||||
|
"and #%b", "and %b=%0", "orc !%c", "rol %b", //28
|
||||||
|
"rol %w", "pha", "bne %b=%R", "bra %r", //2C
|
||||||
|
"bmi %r", "jst $ffd8", "clr %b:1", "bbc %b:1=$R", //30
|
||||||
|
"and %b,x", "and %w,x", "and %w,y", "and (%b),y", //34
|
||||||
|
"and %b=#%0", "and (x)=(y)", "inw %b", "rol $b,x", //38
|
||||||
|
"rol", "inx", "cpx %b", "jsr %w", //3C
|
||||||
|
"sep", "jst $ffd6", "set %b:2", "bbs %b:2=$R", //40
|
||||||
|
"eor %b", "eor %w", "eor (x)", "eor ($b,x)", //44
|
||||||
|
"eor #%b", "eor %b=%0", "and %c", "lsr %b", //48
|
||||||
|
"lsr %w", "phx", "trb %w", "jsp $ff", //4C
|
||||||
|
"bvc %r", "jst $ffd4", "clr %b:2", "bbc %b:2=%R", //50
|
||||||
|
"eor %b,x", "eor %w,x", "eor %w,y", "eor (%b),y", //54
|
||||||
|
"eor %b=#%0", "eor (x)=(y)", "cpw %w", "lsr %b,x", //58
|
||||||
|
"lsr", "tax", "cpy %w", "jmp %w", //5C
|
||||||
|
"clc", "jst $ffd2", "set %b:3", "bbs %b:3=$R", //60
|
||||||
|
"cmp %b", "cmp %w", "cmp (x)", "cmp ($b,x)", //64
|
||||||
|
"cmp #%b", "cmp %b=%0", "and !%c", "ror %b", //68
|
||||||
|
"ror %w", "phy", "bne --$b=%R", "rts", //6C
|
||||||
|
"bvs %r", "jst $ffd0", "clr %b:3", "bbc %b:3=%R", //70
|
||||||
|
"cmp %b,x", "cmp %w,x", "cmp %w,y", "cmp (%b),y", //74
|
||||||
|
"cmp %b=#%0", "cmp (x)=(y)", "adw %w", "ror %b,x", //78
|
||||||
|
"ror", "txa", "cpy %b", "rti", //7C
|
||||||
|
"sec", "jst $ffce", "set %b:4", "bbs %b:4=$R", //80
|
||||||
|
"adc %b", "adc %w", "adc (x)", "adc ($b,x)", //84
|
||||||
|
"adc #%b", "cmp %b=%0", "eor %c", "dec %b", //88
|
||||||
|
"dec %w", "ldy #%b", "plp", "str %b=#%0", //8C
|
||||||
|
"bcc %r", "jst $ffcc", "clr %b:4", "bbc %b:4=%R", //90
|
||||||
|
"adc %b,x", "adc %w,x", "adc %w,y", "adc (%b),y", //94
|
||||||
|
"adc %b=#%0", "adc (x)=(y)", "sbw %w", "dec %b,x", //98
|
||||||
|
"dec", "tsx", "div", "xcn", //9C
|
||||||
|
"sei", "jst $ffca", "set %b:5", "bbs %b:5=$R", //A0
|
||||||
|
"sbc %b", "sbc %w", "sbc (x)", "sbc ($b,x)", //A4
|
||||||
|
"sbc #%b", "sbc %b=%0", "ldc %c", "inc %b", //A8
|
||||||
|
"inc %w", "cpy #%b", "pla", "sta (x++)", //AC
|
||||||
|
"bcs %r", "jst $ffc8", "clr %b:5", "bbc %b:5=%R", //B0
|
||||||
|
"sbc %b,x", "sbc %w,x", "sbc %w,y", "sbc (%b),y", //B4
|
||||||
|
"sbc %b=#%0", "sbc (x)=(y)", "ldw %b", "inc %b,x", //B8
|
||||||
|
"inc", "txs", "das", "lda (x++)", //BC
|
||||||
|
"cli", "jst $ffc6", "set %b:6", "bbs %b:6=$R", //C0
|
||||||
|
"sta %b", "sta %w", "sta (x)", "sta ($b,x)", //C4
|
||||||
|
"cpx #%b", "stx %w", "stc %c", "sty %b", //C8
|
||||||
|
"sty %w", "ldx #%b", "plx", "mul", //CC
|
||||||
|
"bne %r", "jst $ffc4", "clr %b:6", "bbc %b:6=%R", //D0
|
||||||
|
"sta %b,x", "sta %w,x", "sta %w,y", "sta (%b),y", //D4
|
||||||
|
"stx %b", "stx %b,y", "stw %b", "stw %b,x", //D8
|
||||||
|
"dey", "tya", "bne %b,x=%R", "daa", //DC
|
||||||
|
"clv", "jst $ffc2", "set %b:7", "bbs %b:7=$R", //E0
|
||||||
|
"lda %b", "lda %w", "lda (x)", "lda ($b,x)", //E4
|
||||||
|
"lda #%b", "ldx %w", "not %c", "ldy %b", //E8
|
||||||
|
"ldy %w", "cmc", "ply", "wai", //EC
|
||||||
|
"beq %r", "jst $ffc0", "clr %b:7", "bbc %b:7=%R", //F0
|
||||||
|
"lda %b,x", "lda %w,x", "lda %w,y", "lda (%b),y", //F4
|
||||||
|
"ldx %b", "ldx %b,y", "str %b=%0", "ldy %b,x", //F8
|
||||||
|
"iny", "tay", "bne --y=%r", "stp" //FC
|
||||||
|
};
|
||||||
|
|
||||||
|
template<bool laddr, bool lacc>
|
||||||
|
std::string scpu_disassembler<laddr, lacc>::disassemble(uint64_t base, std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
std::ostringstream o;
|
||||||
|
const char* ins = scpu_instructions[fetchpc()];
|
||||||
|
uint8_t x = 0;
|
||||||
|
//Handle %0 specially.
|
||||||
|
for(size_t i = 0; ins[i]; i++)
|
||||||
|
if(ins[i] == '%' && ins[i + 1] == '0')
|
||||||
|
x = fetchpc();
|
||||||
|
|
||||||
|
for(size_t i = 0; ins[i]; i++) {
|
||||||
|
if(ins[i] != '%')
|
||||||
|
o << ins[i];
|
||||||
|
else {
|
||||||
|
switch(ins[i + 1]) {
|
||||||
|
case '0':
|
||||||
|
o << "$" << tohex(x);
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
o << "$" << tohex(fetch_le<typename varsize<lacc>::type_t>(fetchpc));
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
o << "$" << tohex(fetch_le<uint8_t>(fetchpc));
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
o << "$" << tohex(fetch_le<uint8_t>(fetchpc));
|
||||||
|
o << tohex(fetch_le<uint16_t>(fetchpc));
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
o << "$" << tohex(static_cast<uint16_t>(base + 2 +
|
||||||
|
fetch_le<int8_t>(fetchpc)));
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
o << "$" << tohex(static_cast<uint16_t>(base + 3 +
|
||||||
|
fetch_le<int16_t>(fetchpc)));
|
||||||
|
case 'w':
|
||||||
|
o << "$" << tohex(fetch_le<uint16_t>(fetchpc));
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
o << "$" << tohex(fetch_le<typename varsize<laddr>::type_t>(fetchpc));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return o.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ssmp_disassembler::disassemble(uint64_t base, std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
std::ostringstream o;
|
||||||
|
const char* ins = ssmp_instructions[fetchpc()];
|
||||||
|
uint8_t x = 0;
|
||||||
|
uint16_t tmp = 0;
|
||||||
|
//Handle %0 specially.
|
||||||
|
for(size_t i = 0; ins[i]; i++)
|
||||||
|
if(ins[i] == '%' && ins[i + 1] == '0')
|
||||||
|
x = fetchpc();
|
||||||
|
|
||||||
|
for(size_t i = 0; ins[i]; i++) {
|
||||||
|
if(ins[i] != '%')
|
||||||
|
o << ins[i];
|
||||||
|
else {
|
||||||
|
switch(ins[i + 1]) {
|
||||||
|
case '0':
|
||||||
|
o << "$" << tohex(x);
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
o << "$" << tohex(fetch_le<uint8_t>(fetchpc));
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
tmp = fetch_le<uint16_t>(fetchpc);
|
||||||
|
o << "$" << tohex(static_cast<uint16_t>(tmp & 0x1FFF)) << ":" << (tmp >> 13);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
o << "$" << tohex(static_cast<uint16_t>(base + 2 +
|
||||||
|
fetch_le<int8_t>(fetchpc)));
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
o << "$" << tohex(static_cast<uint16_t>(base + 3 +
|
||||||
|
fetch_le<int8_t>(fetchpc)));
|
||||||
|
case 'w':
|
||||||
|
o << "$" << tohex(fetch_le<uint16_t>(fetchpc));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return o.str();
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,6 +61,10 @@ namespace
|
||||||
|
|
||||||
interface_action act_reset(gambatte_core, 0, "Soft reset", "reset", {});
|
interface_action act_reset(gambatte_core, 0, "Soft reset", "reset", {});
|
||||||
|
|
||||||
|
struct interface_device_reg gb_registers[] = {
|
||||||
|
{NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
//Framebuffer.
|
//Framebuffer.
|
||||||
struct framebuffer_info cover_fbinfo = {
|
struct framebuffer_info cover_fbinfo = {
|
||||||
&_pixel_format_rgb32, //Format.
|
&_pixel_format_rgb32, //Format.
|
||||||
|
@ -430,7 +434,8 @@ namespace
|
||||||
do_reset_flag = true;
|
do_reset_flag = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
.get_registers = []() -> const interface_device_reg* { return gb_registers; },
|
||||||
}};
|
}};
|
||||||
|
|
||||||
core_type type_dmg{{
|
core_type type_dmg{{
|
||||||
|
|
|
@ -20,6 +20,10 @@ namespace sky
|
||||||
{5, 4, 6, 7, 0, 3, 2}
|
{5, 4, 6, 7, 0, 3, 2}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct interface_device_reg sky_registers[] = {
|
||||||
|
{NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
//Framebuffer.
|
//Framebuffer.
|
||||||
uint32_t cover_fbmem[320*200];
|
uint32_t cover_fbmem[320*200];
|
||||||
struct framebuffer_info cover_fbinfo = {
|
struct framebuffer_info cover_fbinfo = {
|
||||||
|
@ -326,7 +330,8 @@ namespace sky
|
||||||
},
|
},
|
||||||
.get_core_shortname = []() -> std::string { return "sky"; },
|
.get_core_shortname = []() -> std::string { return "sky"; },
|
||||||
.pre_emulate_frame = [](controller_frame& cf) -> void {},
|
.pre_emulate_frame = [](controller_frame& cf) -> void {},
|
||||||
.execute_action = [](unsigned id, const std::vector<interface_action_paramval>& p) -> void {}
|
.execute_action = [](unsigned id, const std::vector<interface_action_paramval>& p) -> void {},
|
||||||
|
.get_registers = []() -> const interface_device_reg* { return sky_registers; },
|
||||||
}};
|
}};
|
||||||
|
|
||||||
void controller_magic()
|
void controller_magic()
|
||||||
|
|
|
@ -52,6 +52,10 @@ namespace
|
||||||
0, 0 //Offset.
|
0, 0 //Offset.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct interface_device_reg test_registers[] = {
|
||||||
|
{NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
#include "ports.inc"
|
#include "ports.inc"
|
||||||
#include "slots.inc"
|
#include "slots.inc"
|
||||||
#include "regions.inc"
|
#include "regions.inc"
|
||||||
|
@ -172,7 +176,8 @@ namespace
|
||||||
},
|
},
|
||||||
.get_core_shortname = []() -> std::string { return "test"; },
|
.get_core_shortname = []() -> std::string { return "test"; },
|
||||||
.pre_emulate_frame = [](controller_frame& cf) -> void {},
|
.pre_emulate_frame = [](controller_frame& cf) -> void {},
|
||||||
.execute_action = [](unsigned id, const std::vector<interface_action_paramval>& p) -> void {}
|
.execute_action = [](unsigned id, const std::vector<interface_action_paramval>& p) -> void {},
|
||||||
|
.get_registers = []() -> const interface_device_reg* { return test_registers; },
|
||||||
}};
|
}};
|
||||||
|
|
||||||
core_type type_test{{
|
core_type type_test{{
|
||||||
|
|
120
src/interface/disassembler.cpp
Normal file
120
src/interface/disassembler.cpp
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
#include "interface/disassembler.hpp"
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template<typename T, bool be> T fetch_generic(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
size_t b = sizeof(T);
|
||||||
|
T res = 0;
|
||||||
|
for(size_t i = 0; i < b; i++) {
|
||||||
|
size_t bit = 8 * (be ? (b - i - 1) : i);
|
||||||
|
res |= (static_cast<T>(fetchpc()) << bit);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disassembler::disassembler(const std::string& _name)
|
||||||
|
{
|
||||||
|
disasms()[name = _name] = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
disassembler::~disassembler()
|
||||||
|
{
|
||||||
|
disasms().erase(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
disassembler& disassembler::byname(const std::string& name)
|
||||||
|
{
|
||||||
|
if(disasms().count(name))
|
||||||
|
return *disasms()[name];
|
||||||
|
throw std::runtime_error("No such disassembler known");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, disassembler*>& disassembler::disasms()
|
||||||
|
{
|
||||||
|
static std::map<std::string, disassembler*> x;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> int8_t disassembler::fetch_le(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<int8_t, false>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> uint8_t disassembler::fetch_le(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<uint8_t, false>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> int16_t disassembler::fetch_le(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<int16_t, false>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> uint16_t disassembler::fetch_le(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<uint16_t, false>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> int32_t disassembler::fetch_le(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<int32_t, false>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> uint32_t disassembler::fetch_le(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<uint32_t, false>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> int64_t disassembler::fetch_le(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<int64_t, false>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> uint64_t disassembler::fetch_le(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<uint64_t, false>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> int8_t disassembler::fetch_be(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<int8_t, true>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> uint8_t disassembler::fetch_be(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<uint8_t, true>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> int16_t disassembler::fetch_be(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<int16_t, true>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> uint16_t disassembler::fetch_be(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<uint16_t, true>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> int32_t disassembler::fetch_be(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<int32_t, true>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> uint32_t disassembler::fetch_be(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<uint32_t, true>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> int64_t disassembler::fetch_be(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<int64_t, true>(fetchpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> uint64_t disassembler::fetch_be(std::function<unsigned char()> fetchpc)
|
||||||
|
{
|
||||||
|
return fetch_generic<uint64_t, true>(fetchpc);
|
||||||
|
}
|
|
@ -366,6 +366,7 @@ core_core::core_core(const core_core_params& params)
|
||||||
_get_core_shortname = params.get_core_shortname;
|
_get_core_shortname = params.get_core_shortname;
|
||||||
_pre_emulate_frame = params.pre_emulate_frame;
|
_pre_emulate_frame = params.pre_emulate_frame;
|
||||||
_execute_action = params.execute_action;
|
_execute_action = params.execute_action;
|
||||||
|
_get_registers = params.get_registers;
|
||||||
hidden = false;
|
hidden = false;
|
||||||
all_cores_set().insert(this);
|
all_cores_set().insert(this);
|
||||||
if(install_handlers_automatically)
|
if(install_handlers_automatically)
|
||||||
|
@ -519,6 +520,11 @@ void core_core::execute_action(unsigned id, const std::vector<interface_action_p
|
||||||
return _execute_action(id, p);
|
return _execute_action(id, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const struct interface_device_reg* core_core::get_registers()
|
||||||
|
{
|
||||||
|
return _get_registers();
|
||||||
|
}
|
||||||
|
|
||||||
void core_core::do_register_action(const std::string& key, interface_action& act)
|
void core_core::do_register_action(const std::string& key, interface_action& act)
|
||||||
{
|
{
|
||||||
umutex_class h(actions_lock);
|
umutex_class h(actions_lock);
|
||||||
|
|
91
src/lua/disassemble.cpp
Normal file
91
src/lua/disassemble.cpp
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#include "lua/internal.hpp"
|
||||||
|
#include "interface/disassembler.hpp"
|
||||||
|
#include "interface/romtype.hpp"
|
||||||
|
#include "library/bintohex.hpp"
|
||||||
|
#include "core/memorymanip.hpp"
|
||||||
|
#include "core/moviedata.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
function_ptr_luafun memdisass(LS, "memory.disassemble", [](lua_state& L, const std::string& fname) -> int {
|
||||||
|
uint64_t count = 1;
|
||||||
|
std::string kind = L.get_string(1, fname.c_str());
|
||||||
|
uint64_t addr = L.get_numeric_argument<uint64_t>(2, fname.c_str());
|
||||||
|
L.get_numeric_argument<uint64_t>(3, count, fname.c_str());
|
||||||
|
disassembler* d;
|
||||||
|
try {
|
||||||
|
d = &disassembler::byname(kind);
|
||||||
|
} catch(std::exception& e) {
|
||||||
|
L.pushstring(e.what());
|
||||||
|
L.error();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
L.newtable();
|
||||||
|
uint64_t laddr = addr;
|
||||||
|
for(uint64_t i = 1; i <= count; i++) {
|
||||||
|
uint64_t bytes = 0;
|
||||||
|
L.pushnumber(i);
|
||||||
|
L.newtable();
|
||||||
|
L.pushstring("addr");
|
||||||
|
L.pushnumber(laddr);
|
||||||
|
L.settable(-3);
|
||||||
|
|
||||||
|
L.pushstring("disasm");
|
||||||
|
L.pushlstring(d->disassemble(laddr, [&bytes, laddr]() -> unsigned char {
|
||||||
|
return lsnes_memory.read<uint8_t>(laddr + bytes++);
|
||||||
|
}));
|
||||||
|
L.settable(-3);
|
||||||
|
|
||||||
|
std::vector<unsigned char> tmp;
|
||||||
|
tmp.resize(bytes);
|
||||||
|
lsnes_memory.read_range(laddr, &tmp[0], bytes);
|
||||||
|
L.pushstring("bytes");
|
||||||
|
L.pushlstring(binary_to_hex(&tmp[0], bytes));
|
||||||
|
L.settable(-3);
|
||||||
|
L.settable(-3);
|
||||||
|
laddr += bytes;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
function_ptr_luafun getreg(LS, "memory.getregister", [](lua_state& L, const std::string& fname) -> int {
|
||||||
|
std::string r = L.get_string(1, fname.c_str());
|
||||||
|
const interface_device_reg* regs = our_rom->rtype->get_registers();
|
||||||
|
if(!regs) {
|
||||||
|
L.pushnil();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for(size_t i = 0; regs[i].name; i++) {
|
||||||
|
if(r != regs[i].name)
|
||||||
|
continue;
|
||||||
|
if(regs[i].boolean)
|
||||||
|
L.pushboolean(regs[i].read() != 0);
|
||||||
|
else
|
||||||
|
L.pushnumber(regs[i].read());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
L.pushnil();
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
function_ptr_luafun setreg(LS, "memory.setregister", [](lua_state& L, const std::string& fname) -> int {
|
||||||
|
std::string r = L.get_string(1, fname.c_str());
|
||||||
|
const interface_device_reg* regs = our_rom->rtype->get_registers();
|
||||||
|
if(!regs) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for(size_t i = 0; regs[i].name; i++) {
|
||||||
|
if(r != regs[i].name)
|
||||||
|
continue;
|
||||||
|
if(!regs[i].write)
|
||||||
|
break;
|
||||||
|
if(regs[i].boolean)
|
||||||
|
regs[i].write(L.get_bool(2, fname.c_str()) ? 1 : 0);
|
||||||
|
else
|
||||||
|
regs[i].write(L.get_numeric_argument<uint64_t>(2, fname.c_str()));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue