diff options
Diffstat (limited to 'src/devices/machine/netlist.cpp')
-rw-r--r-- | src/devices/machine/netlist.cpp | 488 |
1 files changed, 428 insertions, 60 deletions
diff --git a/src/devices/machine/netlist.cpp b/src/devices/machine/netlist.cpp index 89f4cd017ae..19248d00dc5 100644 --- a/src/devices/machine/netlist.cpp +++ b/src/devices/machine/netlist.cpp @@ -29,7 +29,6 @@ const device_type NETLIST_SOUND = &device_creator<netlist_mame_sound_device_t>; const device_type NETLIST_ANALOG_INPUT = &device_creator<netlist_mame_analog_input_t>; const device_type NETLIST_INT_INPUT = &device_creator<netlist_mame_int_input_t>; -const device_type NETLIST_ROM_REGION = &device_creator<netlist_mame_rom_t>; const device_type NETLIST_RAM_POINTER = &device_creator<netlist_ram_pointer_t>; const device_type NETLIST_LOGIC_INPUT = &device_creator<netlist_mame_logic_input_t>; const device_type NETLIST_STREAM_INPUT = &device_creator<netlist_mame_stream_input_t>; @@ -39,6 +38,391 @@ const device_type NETLIST_ANALOG_OUTPUT = &device_creator<netlist_mame_analog_ou const device_type NETLIST_STREAM_OUTPUT = &device_creator<netlist_mame_stream_output_t>; // ---------------------------------------------------------------------------------------- +// Special netlist extension devices .... +// ---------------------------------------------------------------------------------------- + +class netlist_mame_device_t; + +class netlist_mame_t : public netlist::netlist_t +{ +public: + + netlist_mame_t(netlist_mame_device_t &parent, const pstring &aname) + : netlist::netlist_t(aname), + m_parent(parent) + {} + virtual ~netlist_mame_t() { }; + + inline running_machine &machine(); + + netlist_mame_device_t &parent() { return m_parent; } + +protected: + + void vlog(const plib::plog_level &l, const pstring &ls) const override; + +private: + netlist_mame_device_t &m_parent; +}; + + +// ---------------------------------------------------------------------------------------- +// analog_callback +// ---------------------------------------------------------------------------------------- + +class NETLIB_NAME(analog_callback) : public netlist::device_t +{ +public: + NETLIB_NAME(analog_callback)(netlist::netlist_t &anetlist, const pstring &name) + : device_t(anetlist, name) + , m_in(*this, "IN") + , m_cpu_device(nullptr) + , m_last(*this, "m_last", 0) + { + m_cpu_device = downcast<netlist_mame_cpu_device_t *>(&downcast<netlist_mame_t &>(netlist()).parent()); + } + + ATTR_COLD void reset() override + { + m_last = 0.0; + } + + ATTR_COLD void register_callback(netlist_analog_output_delegate callback) + { + m_callback = callback; + } + + NETLIB_UPDATEI() + { + nl_double cur = m_in(); + + // FIXME: make this a parameter + // avoid calls due to noise + if (std::fabs(cur - m_last) > 1e-6) + { + m_cpu_device->update_time_x(); + m_callback(cur, m_cpu_device->local_time()); + m_cpu_device->check_mame_abort_slice(); + m_last = cur; + } + } + +private: + netlist::analog_input_t m_in; + netlist_analog_output_delegate m_callback; + netlist_mame_cpu_device_t *m_cpu_device; + netlist::state_var<nl_double> m_last; +}; + +// ---------------------------------------------------------------------------------------- +// logic_callback +// ---------------------------------------------------------------------------------------- + +class NETLIB_NAME(logic_callback) : public netlist::device_t +{ +public: + NETLIB_NAME(logic_callback)(netlist::netlist_t &anetlist, const pstring &name) + : device_t(anetlist, name) + , m_in(*this, "IN") + , m_cpu_device(nullptr) + , m_last(*this, "m_last", 0) + { + m_cpu_device = downcast<netlist_mame_cpu_device_t *>(&downcast<netlist_mame_t &>(netlist()).parent()); + } + + ATTR_COLD void reset() override + { + m_last = 0; + } + + ATTR_COLD void register_callback(netlist_logic_output_delegate callback) + { + m_callback = callback; + } + + NETLIB_UPDATEI() + { + netlist_sig_t cur = m_in(); + + // FIXME: make this a parameter + // avoid calls due to noise + if (cur != m_last) + { + m_cpu_device->update_time_x(); + m_callback(cur, m_cpu_device->local_time()); + m_cpu_device->check_mame_abort_slice(); + m_last = cur; + } + } + +private: + netlist::logic_input_t m_in; + netlist_logic_output_delegate m_callback; + netlist_mame_cpu_device_t *m_cpu_device; + netlist::state_var<netlist_sig_t> m_last; +}; + +// ---------------------------------------------------------------------------------------- +// sound_out +// ---------------------------------------------------------------------------------------- + +class NETLIB_NAME(sound_out) : public netlist::device_t +{ +public: + NETLIB_NAME(sound_out)(netlist::netlist_t &anetlist, const pstring &name) + : netlist::device_t(anetlist, name) + , m_channel(*this, "CHAN", 0) + , m_mult(*this, "MULT", 1000.0) + , m_offset(*this, "OFFSET", 0.0) + , m_sample(netlist::netlist_time::from_hz(1)) //sufficiently big enough + , m_in(*this, "IN") + , m_last_buffer(*this, "m_last_buffer", netlist::netlist_time::zero()) + { + } + + static const int BUFSIZE = 2048; + + ATTR_COLD void reset() override + { + m_cur = 0.0; + m_last_pos = 0; + m_last_buffer = netlist::netlist_time::zero(); + } + + ATTR_HOT void sound_update(const netlist::netlist_time &upto) + { + int pos = (upto - m_last_buffer) / m_sample; + if (pos >= BUFSIZE) + netlist().log().fatal("sound {1}: exceeded BUFSIZE\n", name().c_str()); + while (m_last_pos < pos ) + { + m_buffer[m_last_pos++] = (stream_sample_t) m_cur; + } + } + + NETLIB_UPDATEI() + { + nl_double val = m_in() * m_mult() + m_offset(); + sound_update(netlist().time()); + /* ignore spikes */ + if (std::abs(val) < 32767.0) + m_cur = val; + else if (val > 0.0) + m_cur = 32767.0; + else + m_cur = -32767.0; + + } + +public: + ATTR_HOT void buffer_reset(const netlist::netlist_time &upto) + { + m_last_pos = 0; + m_last_buffer = upto; + m_cur = 0.0; + } + + netlist::param_int_t m_channel; + netlist::param_double_t m_mult; + netlist::param_double_t m_offset; + stream_sample_t *m_buffer; + netlist::netlist_time m_sample; + +private: + netlist::analog_input_t m_in; + double m_cur; + int m_last_pos; + netlist::state_var<netlist::netlist_time> m_last_buffer; +}; + +// ---------------------------------------------------------------------------------------- +// sound_in +// ---------------------------------------------------------------------------------------- + +class NETLIB_NAME(sound_in) : public netlist::device_t +{ +public: + NETLIB_NAME(sound_in)(netlist::netlist_t &anetlist, const pstring &name) + : netlist::device_t(anetlist, name) + , m_feedback(*this, "FB") // clock part + , m_Q(*this, "Q") + { + connect(m_feedback, m_Q); + m_inc = netlist::netlist_time::from_nsec(1); + + + for (int i = 0; i < MAX_INPUT_CHANNELS; i++) + { + m_param_name[i] = std::make_unique<netlist::param_str_t>(*this, plib::pfmt("CHAN{1}")(i), ""); + m_param_mult[i] = std::make_unique<netlist::param_double_t>(*this, plib::pfmt("MULT{1}")(i), 1.0); + m_param_offset[i] = std::make_unique<netlist::param_double_t>(*this, plib::pfmt("OFFSET{1}")(i), 0.0); + } + m_num_channel = 0; + } + + static const int MAX_INPUT_CHANNELS = 10; + + ATTR_COLD void reset() override + { + m_pos = 0; + for (auto & elem : m_buffer) + elem = nullptr; + } + + ATTR_COLD int resolve() + { + m_pos = 0; + for (int i = 0; i < MAX_INPUT_CHANNELS; i++) + { + if ((*m_param_name[i])() != pstring("")) + { + if (i != m_num_channel) + netlist().log().fatal("sound input numbering has to be sequential!"); + m_num_channel++; + m_param[i] = dynamic_cast<netlist::param_double_t *>(setup().find_param((*m_param_name[i])(), true)); + } + } + return m_num_channel; + } + + NETLIB_UPDATEI() + { + for (int i=0; i<m_num_channel; i++) + { + if (m_buffer[i] == nullptr) + break; // stop, called outside of stream_update + const nl_double v = m_buffer[i][m_pos]; + m_param[i]->setTo(v * (*m_param_mult[i])() + (*m_param_offset[i])()); + } + m_pos++; + m_Q.push(!m_Q.net().new_Q(), m_inc ); + } + +public: + ATTR_HOT void buffer_reset() + { + m_pos = 0; + } + + std::unique_ptr<netlist::param_str_t> m_param_name[MAX_INPUT_CHANNELS]; + netlist::param_double_t *m_param[MAX_INPUT_CHANNELS]; + stream_sample_t *m_buffer[MAX_INPUT_CHANNELS]; + std::unique_ptr<netlist::param_double_t> m_param_mult[MAX_INPUT_CHANNELS]; + std::unique_ptr<netlist::param_double_t> m_param_offset[MAX_INPUT_CHANNELS]; + netlist::netlist_time m_inc; + +private: + netlist::logic_input_t m_feedback; + netlist::logic_output_t m_Q; + + int m_pos; + int m_num_channel; +}; + +// ---------------------------------------------------------------------------------------- +// Extensions to interface netlist with MAME code .... +// ---------------------------------------------------------------------------------------- + +class netlist_source_memregion_t : public netlist::source_t +{ +public: + netlist_source_memregion_t(netlist::setup_t &setup, pstring name) + : netlist::source_t(setup), m_name(name) + { + } + + virtual std::unique_ptr<plib::pistream> stream(const pstring &name) override; +private: + pstring m_name; +}; + +class netlist_data_memregions_t : public netlist::source_t +{ +public: + netlist_data_memregions_t(netlist::setup_t &setup); + + virtual std::unique_ptr<plib::pistream> stream(const pstring &name) override; +}; + + +netlist::setup_t &netlist_mame_device_t::setup() +{ + return m_netlist->setup(); +} + +void netlist_mame_device_t::register_memregion_source(netlist::setup_t &setup, const char *name) +{ + setup.register_source(plib::make_unique_base<netlist::source_t, netlist_source_memregion_t>(setup, pstring(name, pstring::UTF8))); +} + +running_machine &netlist_mame_t::machine() +{ + return m_parent.machine(); +} + +void netlist_mame_analog_input_t::write(const double val) +{ + if (is_sound_device()) + { + update_to_current_time(); + m_param->setTo(val * m_mult + m_offset); + } + else + { + // FIXME: use device timer .... + m_param->setTo(val * m_mult + m_offset); + } +} + + + +void netlist_mame_int_input_t::write(const uint32_t val) +{ + const uint32_t v = (val >> m_shift) & m_mask; + if (v != (*m_param)()) + synchronize(0, v); +} + +void netlist_mame_logic_input_t::write(const uint32_t val) +{ + const uint32_t v = (val >> m_shift) & 1; + if (v != (*m_param)()) + synchronize(0, v); +} + +void netlist_mame_int_input_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (is_sound_device()) + update_to_current_time(); + m_param->setTo(param); +} + +void netlist_mame_logic_input_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (is_sound_device()) + update_to_current_time(); + m_param->setTo(param); +} + +void netlist_ram_pointer_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_data = (*m_param)(); +} + + +void netlist_mame_cpu_device_t::state_string_export(const device_state_entry &entry, std::string &str) const +{ + if (entry.index() >= 0) + { + if (entry.index() & 1) + str = string_format("%10.6f", *((double *)entry.dataptr())); + else + str = string_format("%d", *((netlist_sig_t *)entry.dataptr())); + } +} + + +// ---------------------------------------------------------------------------------------- // netlist_mame_analog_input_t // ---------------------------------------------------------------------------------------- @@ -68,11 +452,11 @@ void netlist_mame_analog_input_t::static_set_name(device_t &device, const char * void netlist_mame_analog_input_t::device_start() { LOG_DEV_CALLS(("start %s\n", tag())); - netlist::param_t *p = this->nl_owner().setup().find_param(m_param_name); + netlist::param_t *p = this->nl_owner().setup().find_param(pstring(m_param_name, pstring::UTF8)); m_param = dynamic_cast<netlist::param_double_t *>(p); if (m_param == nullptr) { - fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name.c_str()); + fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name); } if (m_mult != 1.0 || m_offset != 0.0) { @@ -103,13 +487,14 @@ void netlist_mame_analog_output_t::static_set_params(device_t &device, const cha void netlist_mame_analog_output_t::custom_netlist_additions(netlist::setup_t &setup) { - pstring dname = "OUT_" + m_in; + const pstring pin(m_in, pstring::UTF8); + pstring dname = "OUT_" + pin; m_delegate.bind_relative_to(owner()->machine().root_device()); plib::owned_ptr<netlist::device_t> dev = plib::owned_ptr<netlist::device_t>::Create<NETLIB_NAME(analog_callback)>(setup.netlist(), setup.build_fqn(dname)); static_cast<NETLIB_NAME(analog_callback) *>(dev.get())->register_callback(m_delegate); setup.netlist().register_dev(std::move(dev)); - setup.register_link(dname + ".IN", m_in); + setup.register_link(dname + ".IN", pin); } void netlist_mame_analog_output_t::device_start() @@ -138,13 +523,14 @@ void netlist_mame_logic_output_t::static_set_params(device_t &device, const char void netlist_mame_logic_output_t::custom_netlist_additions(netlist::setup_t &setup) { - pstring dname = "OUT_" + m_in; + pstring pin(m_in, pstring::UTF8); + pstring dname = "OUT_" + pin; m_delegate.bind_relative_to(owner()->machine().root_device()); plib::owned_ptr<netlist::device_t> dev = plib::owned_ptr<netlist::device_t>::Create<NETLIB_NAME(logic_callback)>(setup.netlist(), setup.build_fqn(dname)); static_cast<NETLIB_NAME(logic_callback) *>(dev.get())->register_callback(m_delegate); setup.netlist().register_dev(std::move(dev)); - setup.register_link(dname + ".IN", m_in); + setup.register_link(dname + ".IN", pin); } void netlist_mame_logic_output_t::device_start() @@ -179,11 +565,11 @@ void netlist_mame_int_input_t::static_set_params(device_t &device, const char *p void netlist_mame_int_input_t::device_start() { LOG_DEV_CALLS(("start %s\n", tag())); - netlist::param_t *p = downcast<netlist_mame_device_t *>(this->owner())->setup().find_param(m_param_name); + netlist::param_t *p = downcast<netlist_mame_device_t *>(this->owner())->setup().find_param(pstring(m_param_name, pstring::UTF8)); m_param = dynamic_cast<netlist::param_int_t *>(p); if (m_param == nullptr) { - fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name.c_str()); + fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name); } } @@ -211,49 +597,14 @@ void netlist_mame_logic_input_t::static_set_params(device_t &device, const char void netlist_mame_logic_input_t::device_start() { LOG_DEV_CALLS(("start %s\n", tag())); - netlist::param_t *p = downcast<netlist_mame_device_t *>(this->owner())->setup().find_param(m_param_name); + netlist::param_t *p = downcast<netlist_mame_device_t *>(this->owner())->setup().find_param(pstring(m_param_name, pstring::UTF8)); m_param = dynamic_cast<netlist::param_logic_t *>(p); if (m_param == nullptr) { - fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name.c_str()); + fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name); } } -// ---------------------------------------------------------------------------------------- -// netlist_mame_rom_t -// ---------------------------------------------------------------------------------------- - -netlist_mame_rom_t::netlist_mame_rom_t(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, NETLIST_ROM_REGION, "Netlist ROM Region", tag, owner, clock, "netlist_rom_region", __FILE__) - , netlist_mame_sub_interface(*owner) - , m_name("") - , m_region_tag(nullptr) - , m_offset(0) - , m_size(0) -{ -} - -void netlist_mame_rom_t::static_set_params(device_t &device, const char *name, const char* region_tag, std::size_t offset, std::size_t size) -{ - netlist_mame_rom_t &r = downcast<netlist_mame_rom_t&>(device); - LOG_DEV_CALLS(("static_set_params %s\n", device.tag())); - r.m_name = name; - r.m_region_tag = region_tag; - r.m_offset = offset; - r.m_size = size; -} - -void netlist_mame_rom_t::custom_netlist_additions(netlist::setup_t &setup) -{ - if (memregion(m_region_tag) == nullptr) - fatalerror("device %s region %s not found\n", basetag(), m_region_tag); - setup.register_source(plib::make_unique_base<netlist::source_t, netlist_data_memregion_t>(setup, - m_name, memregion(m_region_tag)->base() + m_offset, m_size)); -} - -void netlist_mame_rom_t::device_start() -{ -} // ---------------------------------------------------------------------------------------- // netlist_ram_pointer_t @@ -278,11 +629,11 @@ void netlist_ram_pointer_t::static_set_params(device_t &device, const char *para void netlist_ram_pointer_t::device_start() { LOG_DEV_CALLS(("start %s\n", tag())); - netlist::param_t *p = downcast<netlist_mame_device_t *>(this->owner())->setup().find_param(m_param_name); + netlist::param_t *p = downcast<netlist_mame_device_t *>(this->owner())->setup().find_param(pstring(m_param_name, pstring::UTF8)); m_param = dynamic_cast<netlist::param_ptr_t *>(p); if (m_param == nullptr) { - fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name.c_str()); + fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name); } m_data = (*m_param)(); @@ -318,7 +669,7 @@ void netlist_mame_stream_input_t::custom_netlist_additions(netlist::setup_t &set setup.register_dev("NETDEV_SOUND_IN", "STREAM_INPUT"); pstring sparam = plib::pfmt("STREAM_INPUT.CHAN{1}")(m_channel); - setup.register_param(sparam, m_param_name); + setup.register_param(sparam, pstring(m_param_name, pstring::UTF8)); sparam = plib::pfmt("STREAM_INPUT.MULT{1}")(m_channel); setup.register_param(sparam, m_mult); sparam = plib::pfmt("STREAM_INPUT.OFFSET{1}")(m_channel); @@ -360,7 +711,7 @@ void netlist_mame_stream_output_t::custom_netlist_additions(netlist::setup_t &se setup.register_param(sname + ".CHAN" , m_channel); setup.register_param(sname + ".MULT", m_mult); setup.register_param(sname + ".OFFSET", m_offset); - setup.register_link(sname + ".IN", m_out_name); + setup.register_link(sname + ".IN", pstring(m_out_name, pstring::UTF8)); } @@ -399,10 +750,6 @@ void netlist_mame_t::vlog(const plib::plog_level &l, const pstring &ls) const // netlist_mame_device_t // ---------------------------------------------------------------------------------------- -static ADDRESS_MAP_START(program_dummy, AS_PROGRAM, 8, netlist_mame_device_t) - AM_RANGE(0x000, 0x3ff) AM_ROM -ADDRESS_MAP_END - netlist_mame_device_t::netlist_mame_device_t(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, NETLIST_CORE, "Netlist core device", tag, owner, clock, "netlist_core", __FILE__), m_icount(0), @@ -421,6 +768,11 @@ netlist_mame_device_t::netlist_mame_device_t(const machine_config &mconfig, devi { } +netlist_mame_device_t::~netlist_mame_device_t() +{ + pstring::resetmem(); +} + void netlist_mame_device_t::static_set_constructor(device_t &device, void (*setup_func)(netlist::setup_t &)) { LOG_DEV_CALLS(("static_set_constructor\n")); @@ -456,6 +808,9 @@ void netlist_mame_device_t::device_start() } } + /* add default data provider for roms */ + setup().register_source(plib::make_unique_base<netlist::source_t, netlist_data_memregions_t>(setup())); + m_setup_func(setup()); /* let sub-devices tweak the netlist */ @@ -598,7 +953,7 @@ netlist_mame_cpu_device_t::netlist_mame_cpu_device_t(const machine_config &mconf device_state_interface(mconfig, *this), device_disasm_interface(mconfig, *this), device_memory_interface(mconfig, *this), - m_program_config("program", ENDIANNESS_LITTLE, 8, 12, 0, ADDRESS_MAP_NAME(program_dummy)) + m_program_config("program", ENDIANNESS_LITTLE, 8, 12) // Interface is needed to keep debugger happy { } @@ -619,11 +974,11 @@ void netlist_mame_cpu_device_t::device_start() netlist::detail::net_t *n = netlist().m_nets[i].get(); if (n->is_logic()) { - state_add(i*2, n->name().c_str(), downcast<netlist::logic_net_t *>(n)->Q_state_ptr()); + state_add(i*2, n->name().c_str(), *downcast<netlist::logic_net_t *>(n)->Q_state_ptr()); } else { - state_add(i*2+1, n->name().c_str(), downcast<netlist::analog_net_t *>(n)->Q_Analog_state_ptr()).formatstr("%20s"); + state_add(i*2+1, n->name().c_str(), *downcast<netlist::analog_net_t *>(n)->Q_Analog_state_ptr()).formatstr("%20s"); } } @@ -791,11 +1146,24 @@ std::unique_ptr<plib::pistream> netlist_source_memregion_t::stream(const pstring return plib::make_unique_base<plib::pistream, plib::pimemstream>(mem->base(), mem->bytes()); } -std::unique_ptr<plib::pistream> netlist_data_memregion_t::stream(const pstring &name) +netlist_data_memregions_t::netlist_data_memregions_t(netlist::setup_t &setup) +: netlist::source_t(setup, netlist::source_t::DATA) +{ +} + +std::unique_ptr<plib::pistream> netlist_data_memregions_t::stream(const pstring &name) { - if (name == m_name) - return plib::make_unique_base<plib::pistream, plib::pimemstream>(m_ptr, m_size); + memory_region *mem = downcast<netlist_mame_t &>(setup().netlist()).parent().memregion(name.c_str()); + //memory_region *mem = downcast<netlist_mame_t &>(setup().netlist()).machine().root_device().memregion(name.c_str()); + if (mem != nullptr) + { + return plib::make_unique_base<plib::pistream, plib::pimemstream>(mem->base(), mem->bytes()); + } else + { + // This should be the last data provider being called - last resort + fatalerror("data named %s not found in device rom regions\n", name.c_str()); return std::unique_ptr<plib::pistream>(nullptr); + } } |