mirror of
https://github.com/holub/mame
synced 2025-04-19 15:11:37 +03:00
modernise drcuml somewhat (nw)
This commit is contained in:
parent
a8633e35a4
commit
1e1e8eb034
@ -32,13 +32,14 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "emuopts.h"
|
||||
#include "drcuml.h"
|
||||
|
||||
#include "emuopts.h"
|
||||
#include "drcbec.h"
|
||||
#include "drcbex86.h"
|
||||
#include "drcbex64.h"
|
||||
|
||||
using namespace uml;
|
||||
#include <fstream>
|
||||
|
||||
|
||||
|
||||
@ -66,11 +67,11 @@ typedef NATIVE_DRC drcbe_native;
|
||||
// structure describing back-end validation test
|
||||
struct bevalidate_test
|
||||
{
|
||||
opcode_t opcode;
|
||||
uint8_t size;
|
||||
uint8_t iflags;
|
||||
uint8_t flags;
|
||||
uint64_t param[4];
|
||||
uml::opcode_t opcode;
|
||||
u8 size;
|
||||
u8 iflags;
|
||||
u8 flags;
|
||||
u64 param[4];
|
||||
};
|
||||
|
||||
|
||||
@ -84,11 +85,12 @@ struct bevalidate_test
|
||||
//-------------------------------------------------
|
||||
|
||||
drcbe_interface::drcbe_interface(drcuml_state &drcuml, drc_cache &cache, device_t &device)
|
||||
: m_drcuml(drcuml),
|
||||
m_cache(cache),
|
||||
m_device(device),
|
||||
m_state(*(drcuml_machine_state *)cache.alloc_near(sizeof(m_state))),
|
||||
m_accessors(nullptr)
|
||||
: m_drcuml(drcuml)
|
||||
, m_cache(cache)
|
||||
, m_device(device)
|
||||
, m_space()
|
||||
, m_state(*reinterpret_cast<drcuml_machine_state *>(cache.alloc_near(sizeof(m_state))))
|
||||
, m_accessors(nullptr)
|
||||
{
|
||||
// reset the machine state
|
||||
memset(&m_state, 0, sizeof(m_state));
|
||||
@ -97,17 +99,19 @@ drcbe_interface::drcbe_interface(drcuml_state &drcuml, drc_cache &cache, device_
|
||||
device_memory_interface *memory;
|
||||
if (device.interface(memory))
|
||||
{
|
||||
int count = memory->max_space_count();
|
||||
m_accessors = ((data_accessors *)cache.alloc_near(sizeof(*m_accessors) * count));
|
||||
int const count = memory->max_space_count();
|
||||
m_accessors = reinterpret_cast<data_accessors *>(cache.alloc_near(sizeof(*m_accessors) * count));
|
||||
memset(m_accessors, 0, sizeof(*m_accessors) * count);
|
||||
m_space.resize(count, nullptr);
|
||||
|
||||
for (int spacenum = 0; spacenum < count; ++spacenum)
|
||||
{
|
||||
if (memory->has_space(spacenum))
|
||||
{
|
||||
m_space[spacenum] = &memory->space(spacenum);
|
||||
m_space[spacenum]->accessors(m_accessors[spacenum]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,21 +134,19 @@ drcbe_interface::~drcbe_interface()
|
||||
// drcuml_state - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
drcuml_state::drcuml_state(device_t &device, drc_cache &cache, uint32_t flags, int modes, int addrbits, int ignorebits)
|
||||
: m_device(device),
|
||||
m_cache(cache),
|
||||
m_drcbe_interface(device.machine().options().drc_use_c() ?
|
||||
std::unique_ptr<drcbe_interface>{ std::make_unique<drcbe_c>(*this, device, cache, flags, modes, addrbits, ignorebits) } :
|
||||
std::unique_ptr<drcbe_interface>{ std::make_unique<drcbe_native>(*this, device, cache, flags, modes, addrbits, ignorebits) }),
|
||||
m_beintf(*m_drcbe_interface.get()),
|
||||
m_umllog(nullptr)
|
||||
drcuml_state::drcuml_state(device_t &device, drc_cache &cache, u32 flags, int modes, int addrbits, int ignorebits)
|
||||
: m_device(device)
|
||||
, m_cache(cache)
|
||||
, m_beintf(device.machine().options().drc_use_c()
|
||||
? std::unique_ptr<drcbe_interface>{ new drcbe_c(*this, device, cache, flags, modes, addrbits, ignorebits) }
|
||||
: std::unique_ptr<drcbe_interface>{ new drcbe_native(*this, device, cache, flags, modes, addrbits, ignorebits) })
|
||||
, m_umllog(device.machine().options().drc_log_uml()
|
||||
? new std::ofstream(util::string_format("drcuml_%s.asm", device.shortname()))
|
||||
: nullptr)
|
||||
, m_blocklist()
|
||||
, m_handlelist()
|
||||
, m_symlist()
|
||||
{
|
||||
// if we're to log, create the logfile
|
||||
if (device.machine().options().drc_log_uml())
|
||||
{
|
||||
std::string filename = std::string("drcuml_").append(m_device.shortname()).append(".asm");
|
||||
m_umllog = fopen(filename.c_str(), "w");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -154,9 +156,6 @@ drcuml_state::drcuml_state(device_t &device, drc_cache &cache, uint32_t flags, i
|
||||
|
||||
drcuml_state::~drcuml_state()
|
||||
{
|
||||
// close any files
|
||||
if (m_umllog != nullptr)
|
||||
fclose(m_umllog);
|
||||
}
|
||||
|
||||
|
||||
@ -174,22 +173,24 @@ void drcuml_state::reset()
|
||||
m_cache.flush();
|
||||
|
||||
// reset all handle code pointers
|
||||
for (code_handle *handle = m_handlelist.first(); handle != nullptr; handle = handle->next())
|
||||
*handle->m_code = nullptr;
|
||||
for (uml::code_handle &handle : m_handlelist)
|
||||
*handle.codeptr_addr() = nullptr;
|
||||
|
||||
// call the backend to reset
|
||||
m_beintf.reset();
|
||||
m_beintf->reset();
|
||||
|
||||
// do a one-time validation if requested
|
||||
/* if (VALIDATE_BACKEND)
|
||||
{
|
||||
static bool validated = false;
|
||||
if (!validated)
|
||||
{
|
||||
validated = true;
|
||||
validate_backend(this);
|
||||
}
|
||||
}*/
|
||||
#if 0
|
||||
if (VALIDATE_BACKEND)
|
||||
{
|
||||
static bool validated = false;
|
||||
if (!validated)
|
||||
{
|
||||
validated = true;
|
||||
validate_backend(this);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (drcuml_block::abort_compilation &)
|
||||
{
|
||||
@ -205,14 +206,16 @@ void drcuml_state::reset()
|
||||
drcuml_block *drcuml_state::begin_block(uint32_t maxinst)
|
||||
{
|
||||
// find an inactive block that matches our qualifications
|
||||
drcuml_block *bestblock = nullptr;
|
||||
for (drcuml_block *block = m_blocklist.first(); block != nullptr; block = block->next())
|
||||
if (!block->inuse() && block->maxinst() >= maxinst && (bestblock == nullptr || block->maxinst() < bestblock->maxinst()))
|
||||
bestblock = block;
|
||||
drcuml_block *bestblock(nullptr);
|
||||
for (drcuml_block &block : m_blocklist)
|
||||
{
|
||||
if (!block.inuse() && (block.maxinst() >= maxinst) && (!bestblock || (block.maxinst() < bestblock->maxinst())))
|
||||
bestblock = █
|
||||
}
|
||||
|
||||
// if we failed to find one, allocate a new one
|
||||
if (bestblock == nullptr)
|
||||
bestblock = &m_blocklist.append(*global_alloc(drcuml_block(*this, maxinst * 3/2)));
|
||||
if (!bestblock)
|
||||
bestblock = &*m_blocklist.emplace(m_blocklist.end(), *this, maxinst * 3 / 2);
|
||||
|
||||
// start the block
|
||||
bestblock->begin();
|
||||
@ -224,10 +227,10 @@ drcuml_block *drcuml_state::begin_block(uint32_t maxinst)
|
||||
// handle_alloc - allocate a new handle
|
||||
//-------------------------------------------------
|
||||
|
||||
code_handle *drcuml_state::handle_alloc(const char *name)
|
||||
uml::code_handle *drcuml_state::handle_alloc(char const *name)
|
||||
{
|
||||
// allocate the handle, add it to our list, and return it
|
||||
return &m_handlelist.append(*global_alloc(code_handle(*this, name)));
|
||||
return &*m_handlelist.emplace(m_handlelist.end(), *this, name);
|
||||
}
|
||||
|
||||
|
||||
@ -236,9 +239,9 @@ code_handle *drcuml_state::handle_alloc(const char *name)
|
||||
// symbol table
|
||||
//-------------------------------------------------
|
||||
|
||||
void drcuml_state::symbol_add(void *base, uint32_t length, const char *name)
|
||||
void drcuml_state::symbol_add(void *base, u32 length, char const *name)
|
||||
{
|
||||
m_symlist.append(*global_alloc(symbol(base, length, name)));
|
||||
m_symlist.emplace_back(base, length, name);
|
||||
}
|
||||
|
||||
|
||||
@ -248,23 +251,22 @@ void drcuml_state::symbol_add(void *base, uint32_t length, const char *name)
|
||||
// found
|
||||
//-------------------------------------------------
|
||||
|
||||
const char *drcuml_state::symbol_find(void *base, uint32_t *offset)
|
||||
const char *drcuml_state::symbol_find(void *base, u32 *offset)
|
||||
{
|
||||
drccodeptr search = drccodeptr(base);
|
||||
drccodeptr const search(reinterpret_cast<drccodeptr>(base));
|
||||
|
||||
// simple linear search
|
||||
for (symbol *cursym = m_symlist.first(); cursym != nullptr; cursym = cursym->next())
|
||||
if (search >= cursym->m_base && search < cursym->m_base + cursym->m_length)
|
||||
for (symbol const &cursym : m_symlist)
|
||||
{
|
||||
// if no offset pointer, only match perfectly
|
||||
if (cursym.includes(search) && (offset || (cursym.base() == search)))
|
||||
{
|
||||
// if no offset pointer, only match perfectly
|
||||
if (offset == nullptr && search != cursym->m_base)
|
||||
continue;
|
||||
|
||||
// return the offset and name
|
||||
if (offset != nullptr)
|
||||
*offset = search - cursym->m_base;
|
||||
return cursym->m_name.c_str();
|
||||
if (offset)
|
||||
*offset = search - cursym.base();
|
||||
return cursym.name().c_str();
|
||||
}
|
||||
}
|
||||
|
||||
// not found; return nullptr
|
||||
return nullptr;
|
||||
@ -272,22 +274,17 @@ const char *drcuml_state::symbol_find(void *base, uint32_t *offset)
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// log_printf - directly printf to the UML log
|
||||
// log_vprintf - directly printf to the UML log
|
||||
// if generated
|
||||
//-------------------------------------------------
|
||||
|
||||
void drcuml_state::log_printf(const char *format, ...)
|
||||
void drcuml_state::log_vprintf(util::format_argument_pack<std::ostream> const &args)
|
||||
{
|
||||
// if we have a file, print to it
|
||||
if (m_umllog != nullptr)
|
||||
if (m_umllog)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
// do the printf
|
||||
va_start(va, format);
|
||||
vfprintf(m_umllog, format, va);
|
||||
va_end(va);
|
||||
fflush(m_umllog);
|
||||
util::stream_format(*m_umllog, args);
|
||||
m_umllog->flush();
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,13 +298,12 @@ void drcuml_state::log_printf(const char *format, ...)
|
||||
// drcuml_block - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
drcuml_block::drcuml_block(drcuml_state &drcuml, uint32_t maxinst)
|
||||
: m_drcuml(drcuml),
|
||||
m_next(nullptr),
|
||||
m_nextinst(0),
|
||||
m_maxinst(maxinst * 3/2),
|
||||
m_inst(m_maxinst),
|
||||
m_inuse(false)
|
||||
drcuml_block::drcuml_block(drcuml_state &drcuml, u32 maxinst)
|
||||
: m_drcuml(drcuml)
|
||||
, m_nextinst(0)
|
||||
, m_maxinst(maxinst * 3/2)
|
||||
, m_inst(m_maxinst)
|
||||
, m_inuse(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -380,7 +376,7 @@ void drcuml_block::abort()
|
||||
uml::instruction &drcuml_block::append()
|
||||
{
|
||||
// get a pointer to the next instruction
|
||||
instruction &curinst = m_inst[m_nextinst++];
|
||||
uml::instruction &curinst(m_inst[m_nextinst++]);
|
||||
if (m_nextinst > m_maxinst)
|
||||
fatalerror("Overran maxinst in drcuml_block_append\n");
|
||||
|
||||
@ -395,39 +391,39 @@ uml::instruction &drcuml_block::append()
|
||||
|
||||
void drcuml_block::optimize()
|
||||
{
|
||||
uint32_t mapvar[MAPVAR_COUNT] = { 0 };
|
||||
u32 mapvar[uml::MAPVAR_COUNT] = { 0 };
|
||||
|
||||
// iterate over instructions
|
||||
for (int instnum = 0; instnum < m_nextinst; instnum++)
|
||||
{
|
||||
instruction &inst = m_inst[instnum];
|
||||
uml::instruction &inst(m_inst[instnum]);
|
||||
|
||||
// first compute what flags we need
|
||||
uint8_t accumflags = 0;
|
||||
uint8_t remainingflags = inst.output_flags();
|
||||
u8 accumflags(0);
|
||||
u8 remainingflags(inst.output_flags());
|
||||
|
||||
// scan ahead until we run out of possible remaining flags
|
||||
for (int scannum = instnum + 1; remainingflags != 0 && scannum < m_nextinst; scannum++)
|
||||
{
|
||||
// any input flags are required
|
||||
const instruction &scan = m_inst[scannum];
|
||||
uml::instruction const &scan(m_inst[scannum]);
|
||||
accumflags |= scan.input_flags();
|
||||
|
||||
// if the scanahead instruction is unconditional, assume his flags are modified
|
||||
if (scan.condition() == COND_ALWAYS)
|
||||
if (scan.condition() == uml::COND_ALWAYS)
|
||||
remainingflags &= ~scan.modified_flags();
|
||||
}
|
||||
inst.set_flags(accumflags);
|
||||
|
||||
// track mapvars
|
||||
if (inst.opcode() == OP_MAPVAR)
|
||||
mapvar[inst.param(0).mapvar() - MAPVAR_M0] = inst.param(1).immediate();
|
||||
if (inst.opcode() == uml::OP_MAPVAR)
|
||||
mapvar[inst.param(0).mapvar() - uml::MAPVAR_M0] = inst.param(1).immediate();
|
||||
|
||||
// convert all mapvar parameters to immediates
|
||||
else if (inst.opcode() != OP_RECOVER)
|
||||
else if (inst.opcode() != uml::OP_RECOVER)
|
||||
for (int pnum = 0; pnum < inst.numparams(); pnum++)
|
||||
if (inst.param(pnum).is_mapvar())
|
||||
inst.set_mapvar(pnum, mapvar[inst.param(pnum).mapvar() - MAPVAR_M0]);
|
||||
inst.set_mapvar(pnum, mapvar[inst.param(pnum).mapvar() - uml::MAPVAR_M0]);
|
||||
|
||||
// now that flags are correct, simplify the instruction
|
||||
inst.simplify();
|
||||
@ -445,41 +441,43 @@ void drcuml_block::disassemble()
|
||||
std::string comment;
|
||||
|
||||
// iterate over instructions and output
|
||||
int firstcomment = -1;
|
||||
int firstcomment(-1);
|
||||
for (int instnum = 0; instnum < m_nextinst; instnum++)
|
||||
{
|
||||
const instruction &inst = m_inst[instnum];
|
||||
bool flushcomments = false;
|
||||
uml::instruction const &inst(m_inst[instnum]);
|
||||
bool flushcomments(false);
|
||||
|
||||
// remember comments and mapvars for later
|
||||
if (inst.opcode() == OP_COMMENT || inst.opcode() == OP_MAPVAR)
|
||||
if (inst.opcode() == uml::OP_COMMENT || inst.opcode() == uml::OP_MAPVAR)
|
||||
{
|
||||
if (firstcomment == -1)
|
||||
firstcomment = instnum;
|
||||
}
|
||||
|
||||
// print labels, handles, and hashes left justified
|
||||
else if (inst.opcode() == OP_LABEL)
|
||||
m_drcuml.log_printf("$%X:\n", uint32_t(inst.param(0).label()));
|
||||
else if (inst.opcode() == OP_HANDLE)
|
||||
else if (inst.opcode() == uml::OP_LABEL)
|
||||
m_drcuml.log_printf("$%X:\n", u32(inst.param(0).label()));
|
||||
else if (inst.opcode() == uml::OP_HANDLE)
|
||||
m_drcuml.log_printf("%s:\n", inst.param(0).handle().string());
|
||||
else if (inst.opcode() == OP_HASH)
|
||||
m_drcuml.log_printf("(%X,%X):\n", uint32_t(inst.param(0).immediate()), uint32_t(inst.param(1).immediate()));
|
||||
else if (inst.opcode() == uml::OP_HASH)
|
||||
m_drcuml.log_printf("(%X,%X):\n", u32(inst.param(0).immediate()), u32(inst.param(1).immediate()));
|
||||
|
||||
// indent everything else with a tab
|
||||
else
|
||||
{
|
||||
std::string dasm = m_inst[instnum].disasm(&m_drcuml);
|
||||
std::string const dasm(m_inst[instnum].disasm(&m_drcuml));
|
||||
|
||||
// include the first accumulated comment with this line
|
||||
if (firstcomment != -1)
|
||||
{
|
||||
m_drcuml.log_printf("\t%-50.50s; %s\n", dasm.c_str(), get_comment_text(m_inst[firstcomment], comment));
|
||||
m_drcuml.log_printf("\t%-50.50s; %s\n", dasm, get_comment_text(m_inst[firstcomment], comment));
|
||||
firstcomment++;
|
||||
flushcomments = true;
|
||||
}
|
||||
else
|
||||
m_drcuml.log_printf("\t%s\n", dasm.c_str());
|
||||
{
|
||||
m_drcuml.log_printf("\t%s\n", dasm);
|
||||
}
|
||||
}
|
||||
|
||||
// flush any comments pending
|
||||
@ -487,8 +485,8 @@ void drcuml_block::disassemble()
|
||||
{
|
||||
while (firstcomment <= instnum)
|
||||
{
|
||||
const char *text = get_comment_text(m_inst[firstcomment++], comment);
|
||||
if (text != nullptr)
|
||||
char const *const text(get_comment_text(m_inst[firstcomment++], comment));
|
||||
if (text)
|
||||
m_drcuml.log_printf("\t%50s; %s\n", "", text);
|
||||
}
|
||||
firstcomment = -1;
|
||||
@ -504,20 +502,24 @@ void drcuml_block::disassemble()
|
||||
// associated with a comment or mapvar
|
||||
//-------------------------------------------------
|
||||
|
||||
const char *drcuml_block::get_comment_text(const instruction &inst, std::string &comment)
|
||||
char const *drcuml_block::get_comment_text(uml::instruction const &inst, std::string &comment)
|
||||
{
|
||||
// comments return their strings
|
||||
if (inst.opcode() == OP_COMMENT)
|
||||
if (inst.opcode() == uml::OP_COMMENT)
|
||||
{
|
||||
// comments return their strings
|
||||
return comment.assign(inst.param(0).string()).c_str();
|
||||
|
||||
// mapvars comment about their values
|
||||
else if (inst.opcode() == OP_MAPVAR) {
|
||||
comment = string_format("m%d = $%X", (int)inst.param(0).mapvar() - MAPVAR_M0, (uint32_t)inst.param(1).immediate());
|
||||
}
|
||||
else if (inst.opcode() == uml::OP_MAPVAR)
|
||||
{
|
||||
// mapvars comment about their values
|
||||
comment = string_format("m%d = $%X", int(inst.param(0).mapvar() - uml::MAPVAR_M0), u32(inst.param(1).immediate()));
|
||||
return comment.c_str();
|
||||
}
|
||||
|
||||
// everything else is nullptr
|
||||
return nullptr;
|
||||
else
|
||||
{
|
||||
// everything else is nullptr
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -549,12 +551,12 @@ inline uint8_t effective_test_psize(const opcode_info &opinfo, int pnum, int ins
|
||||
return instsize;
|
||||
}
|
||||
|
||||
#define TEST_ENTRY_2(op, size, p1, p2, flags) { OP_##op, size, 0, flags, { U64(p1), U64(p2) } },
|
||||
#define TEST_ENTRY_2F(op, size, p1, p2, iflags, flags) { OP_##op, size, iflags, flags, { U64(p1), U64(p2) } },
|
||||
#define TEST_ENTRY_3(op, size, p1, p2, p3, flags) { OP_##op, size, 0, flags, { U64(p1), U64(p2), U64(p3) } },
|
||||
#define TEST_ENTRY_3F(op, size, p1, p2, p3, iflags, flags) { OP_##op, size, iflags, flags, { U64(p1), U64(p2), U64(p3) } },
|
||||
#define TEST_ENTRY_4(op, size, p1, p2, p3, p4, flags) { OP_##op, size, 0, flags, { U64(p1), U64(p2), U64(p3), U64(p4) } },
|
||||
#define TEST_ENTRY_4F(op, size, p1, p2, p3, p4, iflags, flags) { OP_##op, size, iflags, flags, { U64(p1), U64(p2), U64(p3), U64(p4) } },
|
||||
#define TEST_ENTRY_2(op, size, p1, p2, flags) { OP_##op, size, 0, flags, { u64(p1), u64(p2) } },
|
||||
#define TEST_ENTRY_2F(op, size, p1, p2, iflags, flags) { OP_##op, size, iflags, flags, { u64(p1), u64(p2) } },
|
||||
#define TEST_ENTRY_3(op, size, p1, p2, p3, flags) { OP_##op, size, 0, flags, { u64(p1), u64(p2), u64(p3) } },
|
||||
#define TEST_ENTRY_3F(op, size, p1, p2, p3, iflags, flags) { OP_##op, size, iflags, flags, { u64(p1), u64(p2), u64(p3) } },
|
||||
#define TEST_ENTRY_4(op, size, p1, p2, p3, p4, flags) { OP_##op, size, 0, flags, { u64(p1), u64(p2), u64(p3), u64(p4) } },
|
||||
#define TEST_ENTRY_4F(op, size, p1, p2, p3, p4, iflags, flags) { OP_##op, size, iflags, flags, { u64(p1), u64(p2), u64(p3), u64(p4) } },
|
||||
|
||||
static const bevalidate_test bevalidate_test_list[] =
|
||||
{
|
||||
@ -689,7 +691,7 @@ static const bevalidate_test bevalidate_test_list[] =
|
||||
|
||||
static void validate_backend(drcuml_state *drcuml)
|
||||
{
|
||||
code_handle *handles[3];
|
||||
uml::code_handle *handles[3];
|
||||
int tnum;
|
||||
|
||||
// allocate handles for the code
|
||||
@ -739,7 +741,7 @@ static void validate_backend(drcuml_state *drcuml)
|
||||
or else move on to iterate over the flags
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void bevalidate_iterate_over_params(drcuml_state *drcuml, code_handle **handles, const bevalidate_test *test, parameter *paramlist, int pnum)
|
||||
static void bevalidate_iterate_over_params(drcuml_state *drcuml, uml::code_handle **handles, const bevalidate_test *test, parameter *paramlist, int pnum)
|
||||
{
|
||||
const opcode_info *opinfo = opcode_info_table[test->opcode()];
|
||||
drcuml_ptype ptype;
|
||||
@ -812,7 +814,7 @@ static void bevalidate_iterate_over_params(drcuml_state *drcuml, code_handle **h
|
||||
all supported flag masks
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void bevalidate_iterate_over_flags(drcuml_state *drcuml, code_handle **handles, const bevalidate_test *test, parameter *paramlist)
|
||||
static void bevalidate_iterate_over_flags(drcuml_state *drcuml, uml::code_handle **handles, const bevalidate_test *test, parameter *paramlist)
|
||||
{
|
||||
const opcode_info *opinfo = opcode_info_table[test->opcode()];
|
||||
uint8_t flagmask = opinfo->outflags;
|
||||
@ -831,7 +833,7 @@ static void bevalidate_iterate_over_flags(drcuml_state *drcuml, code_handle **ha
|
||||
results
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void bevalidate_execute(drcuml_state *drcuml, code_handle **handles, const bevalidate_test *test, const parameter *paramlist, uint8_t flagmask)
|
||||
static void bevalidate_execute(drcuml_state *drcuml, uml::code_handle **handles, const bevalidate_test *test, const parameter *paramlist, uint8_t flagmask)
|
||||
{
|
||||
parameter params[ARRAY_LENGTH(test->param)];
|
||||
drcuml_machine_state istate, fstate;
|
||||
@ -1045,7 +1047,7 @@ static int bevalidate_verify_state(drcuml_state *drcuml, const drcuml_machine_st
|
||||
if (opinfo->param[pnum].output & PIO_OUT)
|
||||
{
|
||||
int psize = effective_test_psize(opinfo, pnum, test->size, test->param);
|
||||
uint64_t mask = U64(0xffffffffffffffff) >> (64 - 8 * psize);
|
||||
uint64_t mask = u64(0xffffffffffffffff) >> (64 - 8 * psize);
|
||||
uint64_t result = 0;
|
||||
|
||||
// fetch the result from the parameters
|
||||
|
@ -7,15 +7,19 @@
|
||||
Universal machine language for dynamic recompiling CPU cores.
|
||||
|
||||
***************************************************************************/
|
||||
#ifndef MAME_CPU_DRCUML_H
|
||||
#define MAME_CPU_DRCUML_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef MAME_DEVICES_CPU_DRCUML_H
|
||||
#define MAME_DEVICES_CPU_DRCUML_H
|
||||
|
||||
#include "drccache.h"
|
||||
#include "uml.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// CONSTANTS
|
||||
@ -37,11 +41,11 @@ class drcuml_state;
|
||||
union drcuml_ireg
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
struct { uint32_t l,h; } w; // 32-bit low, high parts of the register
|
||||
struct { u32 l, h; } w; // 32-bit low, high parts of the register
|
||||
#else
|
||||
struct { uint32_t h,l; } w; // 32-bit low, high parts of the register
|
||||
struct { u32 h, l; } w; // 32-bit low, high parts of the register
|
||||
#endif
|
||||
uint64_t d; // 64-bit full register
|
||||
u64 d; // 64-bit full register
|
||||
};
|
||||
|
||||
|
||||
@ -49,47 +53,46 @@ union drcuml_ireg
|
||||
union drcuml_freg
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
struct { float l,h; } s; // 32-bit low, high parts of the register
|
||||
struct { float l, h; } s; // 32-bit low, high parts of the register
|
||||
#else
|
||||
struct { float h,l; } s; // 32-bit low, high parts of the register
|
||||
struct { float h, l; } s; // 32-bit low, high parts of the register
|
||||
#endif
|
||||
double d; // 64-bit full register
|
||||
double d; // 64-bit full register
|
||||
};
|
||||
|
||||
|
||||
// the collected machine state of a system
|
||||
struct drcuml_machine_state
|
||||
{
|
||||
drcuml_ireg r[uml::REG_I_COUNT]; // integer registers
|
||||
drcuml_freg f[uml::REG_F_COUNT]; // floating-point registers
|
||||
uint32_t exp; // exception parameter register
|
||||
uint8_t fmod; // fmod (floating-point mode) register
|
||||
uint8_t flags; // flags state
|
||||
drcuml_ireg r[uml::REG_I_COUNT]; // integer registers
|
||||
drcuml_freg f[uml::REG_F_COUNT]; // floating-point registers
|
||||
u32 exp; // exception parameter register
|
||||
u8 fmod; // fmod (floating-point mode) register
|
||||
u8 flags; // flags state
|
||||
};
|
||||
|
||||
|
||||
// hints and information about the back-end
|
||||
struct drcbe_info
|
||||
{
|
||||
uint8_t direct_iregs; // number of direct-mapped integer registers
|
||||
uint8_t direct_fregs; // number of direct-mapped floating point registers
|
||||
u8 direct_iregs; // number of direct-mapped integer registers
|
||||
u8 direct_fregs; // number of direct-mapped floating point registers
|
||||
};
|
||||
|
||||
|
||||
// a drcuml_block describes a basic block of instructions
|
||||
class drcuml_block
|
||||
{
|
||||
friend class simple_list<drcuml_block>;
|
||||
|
||||
public:
|
||||
// construction/destruction
|
||||
drcuml_block(drcuml_state &drcuml, uint32_t maxinst);
|
||||
drcuml_block(drcuml_state &drcuml, u32 maxinst);
|
||||
drcuml_block(drcuml_block const &) = delete;
|
||||
drcuml_block &operator=(drcuml_block const &) = delete;
|
||||
~drcuml_block();
|
||||
|
||||
// getters
|
||||
drcuml_block *next() const { return m_next; }
|
||||
bool inuse() const { return m_inuse; }
|
||||
uint32_t maxinst() const { return m_maxinst; }
|
||||
u32 maxinst() const { return m_maxinst; }
|
||||
|
||||
// code generation
|
||||
void begin();
|
||||
@ -111,15 +114,14 @@ private:
|
||||
// internal helpers
|
||||
void optimize();
|
||||
void disassemble();
|
||||
const char *get_comment_text(const uml::instruction &inst, std::string &comment);
|
||||
char const *get_comment_text(uml::instruction const &inst, std::string &comment);
|
||||
|
||||
// internal state
|
||||
drcuml_state & m_drcuml; // pointer back to the owning UML
|
||||
drcuml_block * m_next; // pointer to next block
|
||||
uint32_t m_nextinst; // next instruction to fill in the cache
|
||||
uint32_t m_maxinst; // maximum number of instructions
|
||||
std::vector<uml::instruction> m_inst; // pointer to the instruction list
|
||||
bool m_inuse; // this block is in use
|
||||
drcuml_state & m_drcuml; // pointer back to the owning UML
|
||||
u32 m_nextinst; // next instruction to fill in the cache
|
||||
u32 m_maxinst; // maximum number of instructions
|
||||
std::vector<uml::instruction> m_inst; // pointer to the instruction list
|
||||
bool m_inuse; // this block is in use
|
||||
};
|
||||
|
||||
|
||||
@ -127,26 +129,28 @@ private:
|
||||
class drcbe_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
drcbe_interface(drcuml_state &drcuml, drc_cache &cache, device_t &device);
|
||||
// allow deleting through base pointer
|
||||
virtual ~drcbe_interface();
|
||||
|
||||
// required overrides
|
||||
virtual void reset() = 0;
|
||||
virtual int execute(uml::code_handle &entry) = 0;
|
||||
virtual void generate(drcuml_block &block, const uml::instruction *instlist, uint32_t numinst) = 0;
|
||||
virtual bool hash_exists(uint32_t mode, uint32_t pc) = 0;
|
||||
virtual void generate(drcuml_block &block, uml::instruction const *instlist, u32 numinst) = 0;
|
||||
virtual bool hash_exists(u32 mode, u32 pc) = 0;
|
||||
virtual void get_info(drcbe_info &info) = 0;
|
||||
virtual bool logging() const { return false; }
|
||||
|
||||
protected:
|
||||
// base constructor
|
||||
drcbe_interface(drcuml_state &drcuml, drc_cache &cache, device_t &device);
|
||||
|
||||
// internal state
|
||||
drcuml_state & m_drcuml; // pointer back to our owner
|
||||
drc_cache & m_cache; // pointer to the cache
|
||||
device_t & m_device; // CPU device we are associated with
|
||||
std::vector<address_space *> m_space; // pointers to CPU's address space
|
||||
drcuml_machine_state & m_state; // state of the machine (in near cache)
|
||||
data_accessors * m_accessors; // memory accessors (in near cache)
|
||||
drcuml_state & m_drcuml; // pointer back to our owner
|
||||
drc_cache & m_cache; // pointer to the cache
|
||||
device_t & m_device; // CPU device we are associated with
|
||||
std::vector<address_space *> m_space; // pointers to CPU's address space
|
||||
drcuml_machine_state & m_state; // state of the machine (in near cache)
|
||||
data_accessors * m_accessors; // memory accessors (in near cache)
|
||||
};
|
||||
|
||||
|
||||
@ -155,7 +159,7 @@ class drcuml_state
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
drcuml_state(device_t &device, drc_cache &cache, uint32_t flags, int modes, int addrbits, int ignorebits);
|
||||
drcuml_state(device_t &device, drc_cache &cache, u32 flags, int modes, int addrbits, int ignorebits);
|
||||
~drcuml_state();
|
||||
|
||||
// getters
|
||||
@ -164,64 +168,66 @@ public:
|
||||
|
||||
// reset the state
|
||||
void reset();
|
||||
int execute(uml::code_handle &entry) { return m_beintf.execute(entry); }
|
||||
int execute(uml::code_handle &entry) { return m_beintf->execute(entry); }
|
||||
|
||||
// code generation
|
||||
drcuml_block *begin_block(uint32_t maxinst);
|
||||
drcuml_block *begin_block(u32 maxinst);
|
||||
|
||||
// back-end interface
|
||||
void get_backend_info(drcbe_info &info) { m_beintf.get_info(info); }
|
||||
bool hash_exists(uint32_t mode, uint32_t pc) { return m_beintf.hash_exists(mode, pc); }
|
||||
void generate(drcuml_block &block, uml::instruction *instructions, uint32_t count) { m_beintf.generate(block, instructions, count); }
|
||||
void get_backend_info(drcbe_info &info) { m_beintf->get_info(info); }
|
||||
bool hash_exists(u32 mode, u32 pc) { return m_beintf->hash_exists(mode, pc); }
|
||||
void generate(drcuml_block &block, uml::instruction *instructions, u32 count) { m_beintf->generate(block, instructions, count); }
|
||||
|
||||
// handle management
|
||||
uml::code_handle *handle_alloc(const char *name);
|
||||
uml::code_handle *handle_alloc(char const *name);
|
||||
|
||||
// symbol management
|
||||
void symbol_add(void *base, uint32_t length, const char *name);
|
||||
const char *symbol_find(void *base, uint32_t *offset = nullptr);
|
||||
void symbol_add(void *base, u32 length, char const *name);
|
||||
char const *symbol_find(void *base, u32 *offset = nullptr);
|
||||
|
||||
// logging
|
||||
bool logging() const { return (m_umllog != nullptr); }
|
||||
void log_printf(const char *format, ...) ATTR_PRINTF(2,3);
|
||||
void log_flush() { if (logging()) fflush(m_umllog); }
|
||||
bool logging_native() const { return m_beintf.logging(); }
|
||||
bool logging() const { return bool(m_umllog); }
|
||||
template <typename Format, typename... Params>
|
||||
void log_printf(Format &&fmt, Params &&...args)
|
||||
{
|
||||
log_vprintf(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
|
||||
}
|
||||
void log_vprintf(util::format_argument_pack<std::ostream> const &args);
|
||||
void log_flush() { if (logging()) m_umllog->flush(); }
|
||||
bool logging_native() const { return m_beintf->logging(); }
|
||||
|
||||
private:
|
||||
// symbol class
|
||||
class symbol
|
||||
{
|
||||
friend class drcuml_state;
|
||||
friend class simple_list<symbol>;
|
||||
|
||||
// construction/destruction
|
||||
symbol(void *base, uint32_t length, const char *name)
|
||||
: m_next(nullptr),
|
||||
m_base(drccodeptr(base)),
|
||||
m_length(length),
|
||||
m_name(name) { }
|
||||
|
||||
public:
|
||||
// construction/destruction
|
||||
symbol(void *base, u32 length, char const *name)
|
||||
: m_base(reinterpret_cast<drccodeptr>(base))
|
||||
, m_length(length)
|
||||
, m_name(name)
|
||||
{ }
|
||||
|
||||
// getters
|
||||
symbol *next() const { return m_next; }
|
||||
bool includes(drccodeptr search) const { return (m_base <= search) && ((m_base + m_length) > search); }
|
||||
drccodeptr base() const { return m_base; }
|
||||
std::string const &name() const { return m_name; }
|
||||
|
||||
private:
|
||||
// internal state
|
||||
symbol * m_next; // link to the next symbol
|
||||
drccodeptr m_base; // base of the symbol
|
||||
uint32_t m_length; // length of the region covered
|
||||
std::string m_name; // name of the symbol
|
||||
drccodeptr m_base; // base of the symbol
|
||||
u32 m_length; // length of the region covered
|
||||
std::string m_name; // name of the symbol
|
||||
};
|
||||
|
||||
// internal state
|
||||
device_t & m_device; // CPU device we are associated with
|
||||
drc_cache & m_cache; // pointer to the codegen cache
|
||||
std::unique_ptr<drcbe_interface> m_drcbe_interface;
|
||||
drcbe_interface & m_beintf; // backend interface pointer
|
||||
FILE * m_umllog; // handle to the UML logfile
|
||||
simple_list<drcuml_block> m_blocklist; // list of active blocks
|
||||
simple_list<uml::code_handle> m_handlelist; // list of active handles
|
||||
simple_list<symbol> m_symlist; // list of symbols
|
||||
device_t & m_device; // CPU device we are associated with
|
||||
drc_cache & m_cache; // pointer to the codegen cache
|
||||
std::unique_ptr<drcbe_interface> const m_beintf; // backend interface pointer
|
||||
std::unique_ptr<std::ostream> const m_umllog; // handle to the UML logfile
|
||||
std::list<drcuml_block> m_blocklist; // list of active blocks
|
||||
std::list<uml::code_handle> m_handlelist; // list of active handles
|
||||
std::list<symbol> m_symlist; // list of symbols
|
||||
};
|
||||
|
||||
|
||||
@ -239,11 +245,11 @@ template <typename Format, typename... Params>
|
||||
inline void drcuml_block::append_comment(Format &&fmt, Params &&... args)
|
||||
{
|
||||
// do the printf
|
||||
std::string temp(util::string_format(std::forward<Format>(fmt), std::forward<Params>(args)...));
|
||||
std::string const temp(util::string_format(std::forward<Format>(fmt), std::forward<Params>(args)...));
|
||||
|
||||
// allocate space in the cache to hold the comment
|
||||
char *comment = (char *)m_drcuml.cache().alloc_temporary(temp.length() + 1);
|
||||
if (comment != nullptr)
|
||||
char *const comment = reinterpret_cast<char *>(m_drcuml.cache().alloc_temporary(temp.length() + 1));
|
||||
if (comment)
|
||||
{
|
||||
strcpy(comment, temp.c_str());
|
||||
|
||||
@ -253,4 +259,4 @@ inline void drcuml_block::append_comment(Format &&fmt, Params &&... args)
|
||||
}
|
||||
|
||||
|
||||
#endif /* MAME_DEVICES_CPU_DRCUML_H */
|
||||
#endif // MAME_CPU_DRCUML_H
|
||||
|
@ -668,8 +668,8 @@ protected:
|
||||
bool generate_instruction_3f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc);
|
||||
void log_add_disasm_comment(drcuml_block *block, uint32_t pc, uint32_t op);
|
||||
const char *log_desc_flags_to_string(uint32_t flags);
|
||||
void log_register_list(drcuml_state *drcuml, const char *string, const uint32_t *reglist, const uint32_t *regnostarlist);
|
||||
void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent);
|
||||
void log_register_list(const char *string, const uint32_t *reglist, const uint32_t *regnostarlist);
|
||||
void log_opcode_desc(const opcode_desc *desclist, int indent);
|
||||
|
||||
};
|
||||
|
||||
|
@ -389,7 +389,7 @@ void ppc_device::code_compile_block(uint8_t mode, offs_t pc)
|
||||
/* get a description of this sequence */
|
||||
desclist = m_drcfe->describe_code(pc);
|
||||
if (m_drcuml->logging() || m_drcuml->logging_native())
|
||||
log_opcode_desc(m_drcuml.get(), desclist, 0);
|
||||
log_opcode_desc(desclist, 0);
|
||||
|
||||
bool succeeded = false;
|
||||
while (!succeeded)
|
||||
@ -670,29 +670,29 @@ void ppc_device::static_generate_entry_point()
|
||||
alloc_handle(m_drcuml.get(), &m_exception_norecover[EXCEPTION_EI], "exception_ei_norecover");
|
||||
|
||||
alloc_handle(m_drcuml.get(), &m_entry, "entry");
|
||||
UML_HANDLE(block, *m_entry); // handle entry
|
||||
UML_HANDLE(block, *m_entry); // handle entry
|
||||
|
||||
/* reset the FPU mode */
|
||||
UML_AND(block, I0, FPSCR32, 3); // and i0,fpscr,3
|
||||
UML_LOAD(block, I0, &m_fpmode[0], I0, SIZE_BYTE, SCALE_x1); // load i0,fpmode,i0,byte
|
||||
UML_SETFMOD(block, I0); // setfmod i0
|
||||
UML_LOAD(block, I0, &m_fpmode[0], I0, SIZE_BYTE, SCALE_x1); // load i0,fpmode,i0,byte
|
||||
UML_SETFMOD(block, I0); // setfmod i0
|
||||
|
||||
/* load fast integer registers */
|
||||
load_fast_iregs(block); // <load fastregs>
|
||||
load_fast_iregs(block); // <load fastregs>
|
||||
load_fast_fregs(block);
|
||||
|
||||
/* check for interrupts */
|
||||
UML_TEST(block, mem(&m_core->irq_pending), ~0); // test [irq_pending],0
|
||||
UML_JMPc(block, COND_Z, skip); // jmp skip,Z
|
||||
UML_TEST(block, MSR32, MSR_EE); // test msr,MSR_EE
|
||||
UML_JMPc(block, COND_Z, skip); // jmp skip,Z
|
||||
UML_MOV(block, I0, mem(&m_core->pc)); // mov i0,pc
|
||||
UML_TEST(block, mem(&m_core->irq_pending), ~0); // test [irq_pending],0
|
||||
UML_JMPc(block, COND_Z, skip); // jmp skip,Z
|
||||
UML_TEST(block, MSR32, MSR_EE); // test msr,MSR_EE
|
||||
UML_JMPc(block, COND_Z, skip); // jmp skip,Z
|
||||
UML_MOV(block, I0, mem(&m_core->pc)); // mov i0,pc
|
||||
UML_MOV(block, I1, 0); // mov i1,0
|
||||
UML_CALLH(block, *m_exception_norecover[EXCEPTION_EI]); // callh exception_norecover
|
||||
UML_LABEL(block, skip); // skip:
|
||||
UML_CALLH(block, *m_exception_norecover[EXCEPTION_EI]); // callh exception_norecover
|
||||
UML_LABEL(block, skip); // skip:
|
||||
|
||||
/* generate a hash jump via the current mode and PC */
|
||||
UML_HASHJMP(block, mem(&m_core->mode), mem(&m_core->pc), *m_nocode); // hashjmp <mode>,<pc>,nocode
|
||||
UML_HASHJMP(block, mem(&m_core->mode), mem(&m_core->pc), *m_nocode); // hashjmp <mode>,<pc>,nocode
|
||||
|
||||
block->end();
|
||||
}
|
||||
@ -768,25 +768,25 @@ void ppc_device::static_generate_tlb_mismatch()
|
||||
|
||||
/* generate a hash jump via the current mode and PC */
|
||||
alloc_handle(m_drcuml.get(), &m_tlb_mismatch, "tlb_mismatch");
|
||||
UML_HANDLE(block, *m_tlb_mismatch); // handle tlb_mismatch
|
||||
UML_RECOVER(block, I0, MAPVAR_PC); // recover i0,PC
|
||||
UML_HANDLE(block, *m_tlb_mismatch); // handle tlb_mismatch
|
||||
UML_RECOVER(block, I0, MAPVAR_PC); // recover i0,PC
|
||||
UML_SHR(block, I1, I0, 12); // shr i1,i0,12
|
||||
UML_LOAD(block, I2, (void *)vtlb_table(), I1, SIZE_DWORD, SCALE_x4); // load i2,[vtlb],i1,dword
|
||||
UML_MOV(block, mem(&m_core->param0), I0); // mov [param0],i0
|
||||
UML_MOV(block, mem(&m_core->param1), TRANSLATE_FETCH); // mov [param1],TRANSLATE_FETCH
|
||||
UML_CALLC(block, (c_function)cfunc_ppccom_tlb_fill, this); // callc tlbfill,ppc
|
||||
UML_LOAD(block, I1, (void *)vtlb_table(), I1, SIZE_DWORD, SCALE_x4); // load i1,[vtlb],i1,dword
|
||||
UML_TEST(block, I1, VTLB_FETCH_ALLOWED); // test i1,VTLB_FETCH_ALLOWED
|
||||
UML_JMPc(block, COND_Z, isi = label++); // jmp isi,z
|
||||
UML_CMP(block, I2, 0); // cmp i2,0
|
||||
UML_JMPc(block, COND_NZ, exit = label++); // jmp exit,nz
|
||||
UML_HASHJMP(block, mem(&m_core->mode), I0, *m_nocode); // hashjmp <mode>,i0,nocode
|
||||
UML_LABEL(block, exit); // exit:
|
||||
UML_MOV(block, mem(&m_core->pc), I0); // mov <pc>,i0
|
||||
save_fast_iregs(block); // <save fastregs>
|
||||
UML_LOAD(block, I2, (void *)vtlb_table(), I1, SIZE_DWORD, SCALE_x4); // load i2,[vtlb],i1,dword
|
||||
UML_MOV(block, mem(&m_core->param0), I0); // mov [param0],i0
|
||||
UML_MOV(block, mem(&m_core->param1), TRANSLATE_FETCH); // mov [param1],TRANSLATE_FETCH
|
||||
UML_CALLC(block, (c_function)cfunc_ppccom_tlb_fill, this); // callc tlbfill,ppc
|
||||
UML_LOAD(block, I1, (void *)vtlb_table(), I1, SIZE_DWORD, SCALE_x4); // load i1,[vtlb],i1,dword
|
||||
UML_TEST(block, I1, VTLB_FETCH_ALLOWED); // test i1,VTLB_FETCH_ALLOWED
|
||||
UML_JMPc(block, COND_Z, isi = label++); // jmp isi,z
|
||||
UML_CMP(block, I2, 0); // cmp i2,0
|
||||
UML_JMPc(block, COND_NZ, exit = label++); // jmp exit,nz
|
||||
UML_HASHJMP(block, mem(&m_core->mode), I0, *m_nocode); // hashjmp <mode>,i0,nocode
|
||||
UML_LABEL(block, exit); // exit:
|
||||
UML_MOV(block, mem(&m_core->pc), I0); // mov <pc>,i0
|
||||
save_fast_iregs(block); // <save fastregs>
|
||||
save_fast_fregs(block);
|
||||
UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE
|
||||
UML_LABEL(block, isi); // isi:
|
||||
UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE
|
||||
UML_LABEL(block, isi); // isi:
|
||||
if (!(m_cap & PPCCAP_603_MMU))
|
||||
{
|
||||
// DAR gets the address, DSISR gets the 'reason' flags
|
||||
@ -3837,7 +3837,7 @@ const char *ppc_device::log_desc_flags_to_string(uint32_t flags)
|
||||
log_register_list - log a list of GPR registers
|
||||
-------------------------------------------------*/
|
||||
|
||||
void ppc_device::log_register_list(drcuml_state *drcuml, const char *string, const uint32_t *reglist, const uint32_t *regnostarlist)
|
||||
void ppc_device::log_register_list(const char *string, const uint32_t *reglist, const uint32_t *regnostarlist)
|
||||
{
|
||||
static const char *const crtext[4] = { "lt", "gt", "eq", "so" };
|
||||
int count = 0;
|
||||
@ -3848,22 +3848,22 @@ void ppc_device::log_register_list(drcuml_state *drcuml, const char *string, con
|
||||
if (reglist[0] == 0 && reglist[1] == 0 && reglist[2] == 0 && reglist[3] == 0)
|
||||
return;
|
||||
|
||||
drcuml->log_printf("[%s:", string);
|
||||
m_drcuml->log_printf("[%s:", string);
|
||||
|
||||
for (regnum = 0; regnum < 32; regnum++)
|
||||
if (reglist[0] & frontend::REGFLAG_R(regnum))
|
||||
{
|
||||
drcuml->log_printf("%sr%d", (count++ == 0) ? "" : ",", regnum);
|
||||
m_drcuml->log_printf("%sr%d", (count++ == 0) ? "" : ",", regnum);
|
||||
if (regnostarlist != nullptr && !(regnostarlist[0] & frontend::REGFLAG_R(regnum)))
|
||||
drcuml->log_printf("*");
|
||||
m_drcuml->log_printf("*");
|
||||
}
|
||||
|
||||
for (regnum = 0; regnum < 32; regnum++)
|
||||
if (reglist[1] & frontend::REGFLAG_FR(regnum))
|
||||
{
|
||||
drcuml->log_printf("%sfr%d", (count++ == 0) ? "" : ",", regnum);
|
||||
m_drcuml->log_printf("%sfr%d", (count++ == 0) ? "" : ",", regnum);
|
||||
if (regnostarlist != nullptr && !(regnostarlist[1] & frontend::REGFLAG_FR(regnum)))
|
||||
drcuml->log_printf("*");
|
||||
m_drcuml->log_printf("*");
|
||||
}
|
||||
|
||||
for (regnum = 0; regnum < 8; regnum++)
|
||||
@ -3871,68 +3871,68 @@ void ppc_device::log_register_list(drcuml_state *drcuml, const char *string, con
|
||||
{
|
||||
if ((reglist[2] & frontend::REGFLAG_CR(regnum)) == frontend::REGFLAG_CR(regnum) && (regnostarlist == nullptr || (regnostarlist[2] & frontend::REGFLAG_CR(regnum)) == frontend::REGFLAG_CR(regnum)))
|
||||
{
|
||||
drcuml->log_printf("%scr%d", (count++ == 0) ? "" : ",", regnum);
|
||||
m_drcuml->log_printf("%scr%d", (count++ == 0) ? "" : ",", regnum);
|
||||
if (regnostarlist != nullptr && !(regnostarlist[2] & frontend::REGFLAG_CR(regnum)))
|
||||
drcuml->log_printf("*");
|
||||
m_drcuml->log_printf("*");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (crnum = 0; crnum < 4; crnum++)
|
||||
if (reglist[2] & frontend::REGFLAG_CR_BIT(regnum * 4 + crnum))
|
||||
{
|
||||
drcuml->log_printf("%scr%d[%s]", (count++ == 0) ? "" : ",", regnum, crtext[crnum]);
|
||||
m_drcuml->log_printf("%scr%d[%s]", (count++ == 0) ? "" : ",", regnum, crtext[crnum]);
|
||||
if (regnostarlist != nullptr && !(regnostarlist[2] & frontend::REGFLAG_CR_BIT(regnum * 4 + crnum)))
|
||||
drcuml->log_printf("*");
|
||||
m_drcuml->log_printf("*");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reglist[3] & frontend::REGFLAG_XER_CA)
|
||||
{
|
||||
drcuml->log_printf("%sxer_ca", (count++ == 0) ? "" : ",");
|
||||
m_drcuml->log_printf("%sxer_ca", (count++ == 0) ? "" : ",");
|
||||
if (regnostarlist != nullptr && !(regnostarlist[3] & frontend::REGFLAG_XER_CA))
|
||||
drcuml->log_printf("*");
|
||||
m_drcuml->log_printf("*");
|
||||
}
|
||||
if (reglist[3] & frontend::REGFLAG_XER_OV)
|
||||
{
|
||||
drcuml->log_printf("%sxer_ov", (count++ == 0) ? "" : ",");
|
||||
m_drcuml->log_printf("%sxer_ov", (count++ == 0) ? "" : ",");
|
||||
if (regnostarlist != nullptr && !(regnostarlist[3] & frontend::REGFLAG_XER_OV))
|
||||
drcuml->log_printf("*");
|
||||
m_drcuml->log_printf("*");
|
||||
}
|
||||
if (reglist[3] & frontend::REGFLAG_XER_SO)
|
||||
{
|
||||
drcuml->log_printf("%sxer_so", (count++ == 0) ? "" : ",");
|
||||
m_drcuml->log_printf("%sxer_so", (count++ == 0) ? "" : ",");
|
||||
if (regnostarlist != nullptr && !(regnostarlist[3] & frontend::REGFLAG_XER_SO))
|
||||
drcuml->log_printf("*");
|
||||
m_drcuml->log_printf("*");
|
||||
}
|
||||
if (reglist[3] & frontend::REGFLAG_XER_COUNT)
|
||||
{
|
||||
drcuml->log_printf("%sxer_count", (count++ == 0) ? "" : ",");
|
||||
m_drcuml->log_printf("%sxer_count", (count++ == 0) ? "" : ",");
|
||||
if (regnostarlist != nullptr && !(regnostarlist[3] & frontend::REGFLAG_XER_COUNT))
|
||||
drcuml->log_printf("*");
|
||||
m_drcuml->log_printf("*");
|
||||
}
|
||||
if (reglist[3] & frontend::REGFLAG_CTR)
|
||||
{
|
||||
drcuml->log_printf("%sctr", (count++ == 0) ? "" : ",");
|
||||
m_drcuml->log_printf("%sctr", (count++ == 0) ? "" : ",");
|
||||
if (regnostarlist != nullptr && !(regnostarlist[3] & frontend::REGFLAG_CTR))
|
||||
drcuml->log_printf("*");
|
||||
m_drcuml->log_printf("*");
|
||||
}
|
||||
if (reglist[3] & frontend::REGFLAG_LR)
|
||||
{
|
||||
drcuml->log_printf("%slr", (count++ == 0) ? "" : ",");
|
||||
m_drcuml->log_printf("%slr", (count++ == 0) ? "" : ",");
|
||||
if (regnostarlist != nullptr && !(regnostarlist[3] & frontend::REGFLAG_LR))
|
||||
drcuml->log_printf("*");
|
||||
m_drcuml->log_printf("*");
|
||||
}
|
||||
|
||||
for (regnum = 0; regnum < 8; regnum++)
|
||||
if (reglist[3] & frontend::REGFLAG_FPSCR(regnum))
|
||||
{
|
||||
drcuml->log_printf("%sfpscr%d", (count++ == 0) ? "" : ",", regnum);
|
||||
m_drcuml->log_printf("%sfpscr%d", (count++ == 0) ? "" : ",", regnum);
|
||||
if (regnostarlist != nullptr && !(regnostarlist[3] & frontend::REGFLAG_FPSCR(regnum)))
|
||||
drcuml->log_printf("*");
|
||||
m_drcuml->log_printf("*");
|
||||
}
|
||||
|
||||
drcuml->log_printf("] ");
|
||||
m_drcuml->log_printf("] ");
|
||||
}
|
||||
|
||||
|
||||
@ -3940,13 +3940,13 @@ void ppc_device::log_register_list(drcuml_state *drcuml, const char *string, con
|
||||
log_opcode_desc - log a list of descriptions
|
||||
-------------------------------------------------*/
|
||||
|
||||
void ppc_device::log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent)
|
||||
void ppc_device::log_opcode_desc(const opcode_desc *desclist, int indent)
|
||||
{
|
||||
util::ovectorstream buffer;
|
||||
|
||||
/* open the file, creating it if necessary */
|
||||
if (indent == 0)
|
||||
drcuml->log_printf("\nDescriptor list @ %08X\n", desclist->pc);
|
||||
m_drcuml->log_printf("\nDescriptor list @ %08X\n", desclist->pc);
|
||||
|
||||
/* output each descriptor */
|
||||
for ( ; desclist != nullptr; desclist = desclist->next())
|
||||
@ -3955,7 +3955,7 @@ void ppc_device::log_opcode_desc(drcuml_state *drcuml, const opcode_desc *descli
|
||||
buffer.seekp(0);
|
||||
|
||||
/* disassemble the current instruction and output it to the log */
|
||||
if (drcuml->logging() || drcuml->logging_native())
|
||||
if (m_drcuml->logging() || m_drcuml->logging_native())
|
||||
{
|
||||
if (desclist->flags & OPFLAG_VIRTUAL_NOOP)
|
||||
buffer << "<virtual nop>";
|
||||
@ -3966,19 +3966,19 @@ void ppc_device::log_opcode_desc(drcuml_state *drcuml, const opcode_desc *descli
|
||||
buffer << "???";
|
||||
|
||||
buffer.put('\0');
|
||||
drcuml->log_printf("%08X [%08X] t:%08X f:%s: %-30s", desclist->pc, desclist->physpc, desclist->targetpc, log_desc_flags_to_string(desclist->flags), &buffer.vec()[0]);
|
||||
m_drcuml->log_printf("%08X [%08X] t:%08X f:%s: %-30s", desclist->pc, desclist->physpc, desclist->targetpc, log_desc_flags_to_string(desclist->flags), &buffer.vec()[0]);
|
||||
|
||||
/* output register states */
|
||||
log_register_list(drcuml, "use", desclist->regin, nullptr);
|
||||
log_register_list(drcuml, "mod", desclist->regout, desclist->regreq);
|
||||
drcuml->log_printf("\n");
|
||||
log_register_list("use", desclist->regin, nullptr);
|
||||
log_register_list("mod", desclist->regout, desclist->regreq);
|
||||
m_drcuml->log_printf("\n");
|
||||
|
||||
/* if we have a delay slot, output it recursively */
|
||||
if (desclist->delay.first() != nullptr)
|
||||
log_opcode_desc(drcuml, desclist->delay.first(), indent + 1);
|
||||
log_opcode_desc(desclist->delay.first(), indent + 1);
|
||||
|
||||
/* at the end of a sequence add a dividing line */
|
||||
if (desclist->flags & OPFLAG_END_SEQUENCE)
|
||||
drcuml->log_printf("-----\n");
|
||||
m_drcuml->log_printf("-----\n");
|
||||
}
|
||||
}
|
||||
|
@ -257,10 +257,10 @@ inline u64 rol64(u64 source, u8 count)
|
||||
uml::code_handle::code_handle(drcuml_state &drcuml, const char *name)
|
||||
: m_code(reinterpret_cast<drccodeptr *>(drcuml.cache().alloc_near(sizeof(drccodeptr))))
|
||||
, m_string(name)
|
||||
, m_next(nullptr)
|
||||
, m_drcuml(drcuml)
|
||||
{
|
||||
if (m_code == nullptr)
|
||||
(void)m_drcuml; // without this, non-debug builds fail because the asserts are preprocessed out
|
||||
if (!m_code)
|
||||
throw std::bad_alloc();
|
||||
*m_code = nullptr;
|
||||
}
|
||||
|
@ -230,15 +230,11 @@ namespace uml
|
||||
// class describing a global code handle
|
||||
class code_handle
|
||||
{
|
||||
friend class ::drcuml_state;
|
||||
friend class ::simple_list<code_handle>;
|
||||
|
||||
public:
|
||||
// construction/destruction
|
||||
code_handle(drcuml_state &drcuml, const char *name);
|
||||
|
||||
public:
|
||||
// getters
|
||||
code_handle *next() const { return m_next; }
|
||||
drccodeptr codeptr() const { return *m_code; }
|
||||
drccodeptr *codeptr_addr() { return m_code; }
|
||||
char const *string() const { return m_string.c_str(); }
|
||||
@ -250,7 +246,6 @@ namespace uml
|
||||
// internal state
|
||||
drccodeptr * m_code; // pointer in the cache to the associated code
|
||||
std::string m_string; // pointer to string attached to handle
|
||||
code_handle * m_next; // link to next handle in the list
|
||||
drcuml_state & m_drcuml; // pointer to owning object
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user