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_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.
|
||||
*/
|
||||
|
@ -371,6 +382,10 @@ struct core_core_params
|
|||
* Execute action.
|
||||
*/
|
||||
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
|
||||
|
@ -469,6 +484,7 @@ struct core_core
|
|||
void do_unregister_action(const std::string& key);
|
||||
std::set<const interface_action*> get_actions();
|
||||
_param_register_proxy param_register_proxy;
|
||||
const interface_device_reg* get_registers();
|
||||
private:
|
||||
std::string (*_core_identifier)();
|
||||
bool (*_set_region)(core_region& region);
|
||||
|
@ -494,6 +510,7 @@ private:
|
|||
std::string (*_get_core_shortname)();
|
||||
void (*_pre_emulate_frame)(controller_frame& cf);
|
||||
void (*_execute_action)(unsigned id, const std::vector<interface_action_paramval>& p);
|
||||
const interface_device_reg* (*_get_registers)();
|
||||
bool hidden;
|
||||
std::map<std::string, interface_action*> actions;
|
||||
mutex_class actions_lock;
|
||||
|
@ -561,6 +578,7 @@ public:
|
|||
bool is_hidden() { return core->is_hidden(); }
|
||||
void pre_emulate_frame(controller_frame& cf) { return core->pre_emulate_frame(cf); }
|
||||
std::set<const interface_action*> get_actions() { return core->get_actions(); }
|
||||
const interface_device_reg* get_registers() { return core->get_registers(); }
|
||||
private:
|
||||
core_type(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
|
||||
OBJECTS=core.$(OBJECT_SUFFIX)
|
||||
OBJECTS=core.$(OBJECT_SUFFIX) scpu-disasm.$(OBJECT_SUFFIX)
|
||||
BSNES_CFLAGS=
|
||||
BSNES_LDFLAGS=
|
||||
ifdef BSNES_IS_COMPAT
|
||||
|
|
|
@ -94,6 +94,56 @@ namespace
|
|||
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 "slots.inc"
|
||||
#include "regions.inc"
|
||||
|
@ -867,7 +917,8 @@ again2:
|
|||
do_hreset_flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
.get_registers = []() -> const interface_device_reg* { return snes_registers; },
|
||||
}};
|
||||
|
||||
core_type type_snes{{
|
||||
|
@ -937,49 +988,6 @@ again2:
|
|||
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
|
||||
char snes_debug_cb_keys[SNES::Debugger::Breakpoints];
|
||||
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", {});
|
||||
|
||||
struct interface_device_reg gb_registers[] = {
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
//Framebuffer.
|
||||
struct framebuffer_info cover_fbinfo = {
|
||||
&_pixel_format_rgb32, //Format.
|
||||
|
@ -430,7 +434,8 @@ namespace
|
|||
do_reset_flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
.get_registers = []() -> const interface_device_reg* { return gb_registers; },
|
||||
}};
|
||||
|
||||
core_type type_dmg{{
|
||||
|
|
|
@ -20,6 +20,10 @@ namespace sky
|
|||
{5, 4, 6, 7, 0, 3, 2}
|
||||
};
|
||||
|
||||
struct interface_device_reg sky_registers[] = {
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
//Framebuffer.
|
||||
uint32_t cover_fbmem[320*200];
|
||||
struct framebuffer_info cover_fbinfo = {
|
||||
|
@ -326,7 +330,8 @@ namespace sky
|
|||
},
|
||||
.get_core_shortname = []() -> std::string { return "sky"; },
|
||||
.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()
|
||||
|
|
|
@ -52,6 +52,10 @@ namespace
|
|||
0, 0 //Offset.
|
||||
};
|
||||
|
||||
struct interface_device_reg test_registers[] = {
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
#include "ports.inc"
|
||||
#include "slots.inc"
|
||||
#include "regions.inc"
|
||||
|
@ -172,7 +176,8 @@ namespace
|
|||
},
|
||||
.get_core_shortname = []() -> std::string { return "test"; },
|
||||
.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{{
|
||||
|
|
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;
|
||||
_pre_emulate_frame = params.pre_emulate_frame;
|
||||
_execute_action = params.execute_action;
|
||||
_get_registers = params.get_registers;
|
||||
hidden = false;
|
||||
all_cores_set().insert(this);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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