modernise drcuml somewhat (nw)

This commit is contained in:
Vas Crabb 2018-03-24 03:53:40 +11:00
parent a8633e35a4
commit 1e1e8eb034
6 changed files with 282 additions and 279 deletions

View File

@ -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 = &block;
}
// 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

View File

@ -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

View File

@ -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);
};

View File

@ -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");
}
}

View File

@ -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;
}

View File

@ -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
};