device_state_interface overhaul

- device_state_entry::value and device_state_entry::set_value now do everything except the register lookup, allowing them to be made public. The debugger expression engine now uses these.
- device_state_entry::dvalue and device_state_entry::set_dvalue have also been made public, theoretically permitting outside code layers to inspect and modify floating-point registers.
- The double specialization of device_pseudo_state_register (now renamed device_functional_state_register) has been added to the core.
- state_add now has an additional specialization that takes both a reference and a write function, using the former for reads only.
- state_max_length has been eliminated in favor of obtaining the relevant info through device_state_entry::max_length.
- The debugger state view no longer adds "flags" as "???" if none have been registered.
- set_state_string has been removed. It was never properly implemented, and it is difficult to see how it could have been done in a useful and consistent way.
- state_find_entry and its typical callers state_int and set_state_int have been inlined for some hopeful efficiency gains.
This commit is contained in:
AJR 2020-08-30 23:39:18 -04:00
parent 71bcb539fe
commit 46071c487e
5 changed files with 202 additions and 204 deletions

View File

@ -1238,35 +1238,6 @@ netlist_mame_cpu_device::netlist_mame_cpu_device(const machine_config &mconfig,
}
// Fixes overflow error in device_pseudo_state_register
template<>
class device_pseudo_state_register<double> : public device_state_entry
{
public:
typedef typename std::function<double ()> getter_func;
typedef typename std::function<void (double)> setter_func;
// construction/destruction
device_pseudo_state_register(int index, const char *symbol, getter_func &&getter, setter_func &&setter, device_state_interface *dev)
: device_state_entry(index, symbol, sizeof(double), ~u64(0), DSF_FLOATING_POINT, dev),
m_getter(std::move(getter)),
m_setter(std::move(setter))
{
}
protected:
// device_state_entry overrides
virtual u64 entry_value() const override { return u64(m_getter()); }
virtual void entry_set_value(u64 value) const override { m_setter(double(value)); }
virtual double entry_dvalue() const override { return m_getter(); }
virtual void entry_set_dvalue(double value) const override { m_setter(value); }
private:
getter_func m_getter; // function to retrieve the data
setter_func m_setter; // function to store the data
};
void netlist_mame_cpu_device::device_start()
{
LOGDEVCALLS("device_start entry\n");
@ -1299,12 +1270,11 @@ void netlist_mame_cpu_device::device_start()
else
{
auto nl = downcast<netlist::analog_net_t *>(n.get());
state_add(std::make_unique<device_pseudo_state_register<double>>(
state_add<double>(
index++,
name.c_str(),
[nl]() { return nl->Q_Analog(); },
[nl](double data) { nl->set_Q_Analog(data); },
this));
[nl](double data) { nl->set_Q_Analog(data); });
}
}

View File

@ -513,8 +513,8 @@ device_debug::device_debug(device_t &device)
strmakelower(tempstr.assign(entry->symbol()));
m_symtable->add(
tempstr.c_str(),
std::bind(&device_state_interface::state_int, m_state, entry->index()),
entry->writeable() ? std::bind(&device_state_interface::set_state_int, m_state, entry->index(), _1) : symbol_table::setter_func(nullptr),
std::bind(&device_state_entry::value, entry.get()),
entry->writeable() ? std::bind(&device_state_entry::set_value, entry.get(), _1) : symbol_table::setter_func(nullptr),
entry->format_string());
}
}

View File

@ -147,7 +147,9 @@ void debug_view_state::recompute()
}
// add a flags entry: flags:xxxxxxxx
m_state_list.emplace_back(STATE_GENFLAGS, "flags", source.m_stateintf->state_string_max_length(STATE_GENFLAGS));
const device_state_entry *flags = source.m_stateintf->state_find_entry(STATE_GENFLAGS);
if (flags != nullptr)
m_state_list.emplace_back(STATE_GENFLAGS, "flags", flags->max_length());
// add a divider entry
m_state_list.emplace_back(REG_DIVIDER, "", 0);
@ -158,7 +160,7 @@ void debug_view_state::recompute()
if (entry->divider())
m_state_list.emplace_back(REG_DIVIDER, "", 0);
else if (entry->visible())
m_state_list.emplace_back(entry->index(), entry->symbol(), source.m_stateintf->state_string_max_length(entry->index()));
m_state_list.emplace_back(entry->index(), entry->symbol(), entry->max_length());
}
// count the entries and determine the maximum tag and value sizes

View File

@ -138,6 +138,36 @@ void device_state_entry::format_from_mask()
}
//-------------------------------------------------
// value - return the current value as a u64
//-------------------------------------------------
u64 device_state_entry::value() const
{
// call the exporter before we do anything
if ((m_flags & DSF_EXPORT) != 0)
m_device_state->state_export(*this);
// pick up the value
return entry_value() & m_datamask;
}
//-------------------------------------------------
// dvalue - return the current value as a double
//-------------------------------------------------
double device_state_entry::dvalue() const
{
// call the exporter before we do anything
if ((m_flags & DSF_EXPORT) != 0)
m_device_state->state_export(*this);
// pick up the value
return entry_dvalue();
}
//-------------------------------------------------
// entry_baseptr - return a pointer to where the
// data lives (if applicable)
@ -178,7 +208,7 @@ double device_state_entry::entry_dvalue() const
std::string device_state_entry::format(const char *string, bool maxout) const
{
std::string dest;
u64 result = value();
u64 result = entry_value() & m_datamask;
// parse the format
bool leadzero = false;
@ -359,6 +389,37 @@ std::string device_state_entry::format(const char *string, bool maxout) const
}
//-------------------------------------------------
// to_string - return the value of the given
// piece of indexed state as a string
//-------------------------------------------------
std::string device_state_entry::to_string() const
{
// get the custom string if needed
std::string custom;
if ((m_flags & DSF_CUSTOM_STRING) != 0)
m_device_state->state_string_export(*this, custom);
else if ((m_flags & DSF_FLOATING_POINT) != 0)
custom = string_format("%-12G", entry_dvalue());
// ask the entry to format itself
return format(custom.c_str());
}
//-------------------------------------------------
// max_length - return the maximum length of the
// given state as a string
//-------------------------------------------------
int device_state_entry::max_length() const
{
// ask the entry to format itself maximally
return format("", true).length();
}
//-------------------------------------------------
// set_value - set the value from a u64
//-------------------------------------------------
@ -376,6 +437,10 @@ void device_state_entry::set_value(u64 value) const
// store the value
entry_set_value(value);
// call the importer to finish up
if ((m_flags & DSF_IMPORT) != 0)
m_device_state->state_import(*this);
}
@ -389,6 +454,10 @@ void device_state_entry::set_dvalue(double value) const
// store the value
entry_set_dvalue(value);
// call the importer to finish up
if ((m_flags & DSF_IMPORT) != 0)
m_device_state->state_import(*this);
}
@ -411,16 +480,6 @@ void device_state_entry::entry_set_dvalue(double value) const
}
//-------------------------------------------------
// set_value - set the value from a string
//-------------------------------------------------
void device_state_entry::set_value(const char *string) const
{
// not implemented
}
//**************************************************************************
// DEVICE STATE INTERFACE
@ -449,110 +508,6 @@ device_state_interface::~device_state_interface()
}
//-------------------------------------------------
// state_int - return the value of the given piece
// of indexed state as a u64
//-------------------------------------------------
u64 device_state_interface::state_int(int index)
{
// nullptr or out-of-range entry returns 0
const device_state_entry *entry = state_find_entry(index);
if (entry == nullptr)
return 0;
// call the exporter before we do anything
if (entry->needs_export())
state_export(*entry);
// pick up the value
return entry->value();
}
//-------------------------------------------------
// state_string - return the value of the given
// pieces of indexed state as a string
//-------------------------------------------------
std::string device_state_interface::state_string(int index) const
{
// nullptr or out-of-range entry returns bogus string
const device_state_entry *entry = state_find_entry(index);
if (entry == nullptr)
return std::string("???");
// get the custom string if needed
std::string custom;
if (entry->needs_custom_string())
state_string_export(*entry, custom);
else if (entry->is_float())
custom = string_format("%-12G", entry->dvalue());
// ask the entry to format itself
return entry->format(custom.c_str());
}
//-------------------------------------------------
// state_string_max_length - return the maximum
// length of the given state string
//-------------------------------------------------
int device_state_interface::state_string_max_length(int index)
{
// nullptr or out-of-range entry returns bogus string
const device_state_entry *entry = state_find_entry(index);
if (entry == nullptr)
return 3;
// ask the entry to format itself maximally
return entry->format("", true).length();
}
//-------------------------------------------------
// set_state_int - set the value of the given
// piece of indexed state from a u64
//-------------------------------------------------
void device_state_interface::set_state_int(int index, u64 value)
{
// nullptr or out-of-range entry is a no-op
const device_state_entry *entry = state_find_entry(index);
if (entry == nullptr)
return;
// set the value
entry->set_value(value);
// call the importer to finish up
if (entry->needs_import())
state_import(*entry);
}
//-------------------------------------------------
// set_state - set the value of the given piece
// of indexed state from a string
//-------------------------------------------------
void device_state_interface::set_state_string(int index, const char *string)
{
// nullptr or out-of-range entry is a no-op
const device_state_entry *entry = state_find_entry(index);
if (entry == nullptr)
return;
// set the value
entry->set_value(string);
// call the importer to finish up
if (entry->needs_import())
state_import(*entry);
}
//-------------------------------------------------
// state_add - add a new piece of indexed state
//-------------------------------------------------
@ -626,24 +581,3 @@ void device_state_interface::interface_post_start()
if (m_state_list.size() == 0)
throw emu_fatalerror("No state registered for device '%s' that supports it!", device().tag());
}
//-------------------------------------------------
// state_find_entry - return a pointer to the
// state entry for the given index
//-------------------------------------------------
const device_state_entry *device_state_interface::state_find_entry(int index) const
{
// use fast lookup if possible
if (index >= FAST_STATE_MIN && index <= FAST_STATE_MAX)
return m_fast_state[index - FAST_STATE_MIN];
// otherwise, scan the first
for (auto &entry : m_state_list)
if (entry->m_index == index)
return entry.get();
// handle failure by returning nullptr
return nullptr;
}

View File

@ -43,7 +43,6 @@ enum
// class describing a single item of exposed device state
class device_state_entry
{
friend class device_state_interface;
public:
// construction/destruction
device_state_entry(int index, const char *symbol, u8 size, u64 sizemask, u8 flags, device_state_interface *dev);
@ -73,6 +72,18 @@ public:
device_state_interface *parent_state() const {return m_device_state;}
const std::string &format_string() const { return m_format; }
// return the current value
u64 value() const;
double dvalue() const;
// return the current value as a string
std::string to_string() const;
int max_length() const;
// set the current value
void set_value(u64 value) const;
void set_dvalue(double value) const;
protected:
// device state flags
static constexpr u8 DSF_NOSHOW = 0x01; // don't display this entry in the registers view
@ -84,22 +95,6 @@ protected:
static constexpr u8 DSF_READONLY = 0x40; // set if this entry does not permit writes
static constexpr u8 DSF_FLOATING_POINT = 0x80; // set if this entry represents a floating-point value
// helpers
bool needs_custom_string() const { return ((m_flags & DSF_CUSTOM_STRING) != 0); }
void format_from_mask();
// return the current value -- only for our friends who handle export
bool needs_export() const { return ((m_flags & DSF_EXPORT) != 0); }
u64 value() const { return entry_value() & m_datamask; }
double dvalue() const { return entry_dvalue(); }
std::string format(const char *string, bool maxout = false) const;
// set the current value -- only for our friends who handle import
bool needs_import() const { return ((m_flags & DSF_IMPORT) != 0); }
void set_value(u64 value) const;
void set_dvalue(double value) const;
void set_value(const char *string) const;
// overrides
virtual void *entry_baseptr() const;
virtual u64 entry_value() const;
@ -107,6 +102,11 @@ protected:
virtual double entry_dvalue() const;
virtual void entry_set_dvalue(double value) const;
private:
// helpers
void format_from_mask();
std::string format(const char *string, bool maxout = false) const;
// statics
static const u64 k_decimal_divisor[20]; // divisors for outputting decimal values
@ -195,18 +195,47 @@ private:
};
// ======================> device_state_register
// ======================> device_latched_functional_state_register
// class template representing a state register of a specific width
template<class ItemType>
class device_pseudo_state_register : public device_state_entry
class device_latched_functional_state_register : public device_state_entry
{
public:
typedef typename std::function<void (ItemType)> setter_func;
// construction/destruction
device_latched_functional_state_register(int index, const char *symbol, ItemType &data, setter_func &&setter, device_state_interface *dev)
: device_state_entry(index, symbol, sizeof(ItemType), std::numeric_limits<ItemType>::max(), 0, dev),
m_data(data),
m_setter(std::move(setter))
{
}
protected:
// device_state_entry overrides
virtual void *entry_baseptr() const override { return &m_data; }
virtual u64 entry_value() const override { return m_data; }
virtual void entry_set_value(u64 value) const override { m_setter(value); }
private:
ItemType & m_data; // reference to where the data lives
setter_func m_setter; // function to store the data
};
// ======================> device_functional_state_register
// class template representing a state register of a specific width
template<class ItemType>
class device_functional_state_register : public device_state_entry
{
public:
typedef typename std::function<ItemType ()> getter_func;
typedef typename std::function<void (ItemType)> setter_func;
// construction/destruction
device_pseudo_state_register(int index, const char *symbol, getter_func &&getter, setter_func &&setter, device_state_interface *dev)
device_functional_state_register(int index, const char *symbol, getter_func &&getter, setter_func &&setter, device_state_interface *dev)
: device_state_entry(index, symbol, sizeof(ItemType), std::numeric_limits<ItemType>::max(), 0, dev),
m_getter(std::move(getter)),
m_setter(std::move(setter))
@ -223,12 +252,41 @@ private:
setter_func m_setter; // function to store the data
};
template<>
class device_functional_state_register<double> : public device_state_entry
{
public:
typedef typename std::function<double ()> getter_func;
typedef typename std::function<void (double)> setter_func;
// construction/destruction
device_functional_state_register(int index, const char *symbol, getter_func &&getter, setter_func &&setter, device_state_interface *dev)
: device_state_entry(index, symbol, sizeof(double), ~u64(0), DSF_FLOATING_POINT, dev),
m_getter(std::move(getter)),
m_setter(std::move(setter))
{
}
protected:
// device_state_entry overrides
virtual u64 entry_value() const override { return u64(m_getter()); }
virtual void entry_set_value(u64 value) const override { m_setter(double(value)); }
virtual double entry_dvalue() const override { return m_getter(); }
virtual void entry_set_dvalue(double value) const override { m_setter(value); }
private:
getter_func m_getter; // function to retrieve the data
setter_func m_setter; // function to store the data
};
// ======================> device_state_interface
// class representing interface-specific live state
class device_state_interface : public device_interface
{
friend class device_state_entry;
public:
// construction/destruction
device_state_interface(const machine_config &mconfig, device_t &device);
@ -238,17 +296,15 @@ public:
const std::vector<std::unique_ptr<device_state_entry>> &state_entries() const { return m_state_list; }
// state getters
u64 state_int(int index);
std::string state_string(int index) const;
int state_string_max_length(int index);
u64 state_int(int index) { const device_state_entry *entry = state_find_entry(index); return (entry == nullptr) ? 0 : entry->value(); }
std::string state_string(int index) const { const device_state_entry *entry = state_find_entry(index); return (entry == nullptr) ? std::string("???") : entry->to_string(); }
offs_t pc() { return state_int(STATE_GENPC); }
offs_t pcbase() { return state_int(STATE_GENPCBASE); }
offs_t sp() { return state_int(STATE_GENSP); }
u64 flags() { return state_int(STATE_GENFLAGS); }
// state setters
void set_state_int(int index, u64 value);
void set_state_string(int index, const char *string);
void set_state_int(int index, u64 value) { const device_state_entry *entry = state_find_entry(index); if (entry != nullptr) entry->set_value(value); }
void set_pc(offs_t pc) { set_state_int(STATE_GENPC, pc); }
// find the entry for a given index
@ -267,19 +323,29 @@ public: // protected eventually
return state_add(std::make_unique<device_state_register<ItemType>>(index, symbol, data, this));
}
// add a new state pseudo-register item (template argument must be explicit)
template<class ItemType> device_state_entry &state_add(int index, const char *symbol,
typename device_pseudo_state_register<ItemType>::getter_func &&getter,
typename device_pseudo_state_register<ItemType>::setter_func &&setter)
// add a new state register item using functional setter
template<class ItemType> device_state_entry &state_add(int index, const char *symbol, ItemType &data,
typename device_latched_functional_state_register<ItemType>::setter_func &&setter)
{
assert(symbol != nullptr);
return state_add(std::make_unique<device_pseudo_state_register<ItemType>>(index, symbol, std::move(getter), std::move(setter), this));
return state_add(std::make_unique<device_latched_functional_state_register<ItemType>>(index, symbol, data, std::move(setter), this));
}
// add a new state register item using functional getter and setter (template argument must be explicit)
template<class ItemType> device_state_entry &state_add(int index, const char *symbol,
typename device_pseudo_state_register<ItemType>::getter_func &&getter)
typename device_functional_state_register<ItemType>::getter_func &&getter,
typename device_functional_state_register<ItemType>::setter_func &&setter)
{
assert(symbol != nullptr);
return state_add(std::make_unique<device_pseudo_state_register<ItemType>>(index, symbol, std::move(getter), [](ItemType){}, this)).readonly();
return state_add(std::make_unique<device_functional_state_register<ItemType>>(index, symbol, std::move(getter), std::move(setter), this));
}
// add a new read-only state register item using functional getter (template argument must be explicit)
template<class ItemType> device_state_entry &state_add(int index, const char *symbol,
typename device_functional_state_register<ItemType>::getter_func &&getter)
{
assert(symbol != nullptr);
return state_add(std::make_unique<device_functional_state_register<ItemType>>(index, symbol, std::move(getter), [](ItemType){}, this)).readonly();
}
device_state_entry &state_add(std::unique_ptr<device_state_entry> &&entry);
@ -310,4 +376,30 @@ protected:
// iterator
typedef device_interface_iterator<device_state_interface> state_interface_iterator;
//**************************************************************************
// INLINE FUNCTIONS
//**************************************************************************
//-------------------------------------------------
// state_find_entry - return a pointer to the
// state entry for the given index
//-------------------------------------------------
inline const device_state_entry *device_state_interface::state_find_entry(int index) const
{
// use fast lookup if possible
if (index >= FAST_STATE_MIN && index <= FAST_STATE_MAX)
return m_fast_state[index - FAST_STATE_MIN];
// otherwise, scan the first
for (auto &entry : m_state_list)
if (entry->index() == index)
return entry.get();
// handle failure by returning nullptr
return nullptr;
}
#endif /* MAME_EMU_DISTATE_H */