mirror of
https://github.com/holub/mame
synced 2025-10-06 09:00:04 +03:00
662 lines
20 KiB
C++
662 lines
20 KiB
C++
// license:GPL-2.0+
|
|
// copyright-holders:Couriersud
|
|
/***************************************************************************
|
|
|
|
netlist.c
|
|
|
|
Discrete netlist implementation.
|
|
|
|
****************************************************************************/
|
|
|
|
#include "emu.h"
|
|
#include "netlist.h"
|
|
#include "netlist/nl_base.h"
|
|
#include "netlist/nl_setup.h"
|
|
#include "netlist/nl_factory.h"
|
|
#include "netlist/nl_parser.h"
|
|
#include "netlist/devices/net_lib.h"
|
|
#include "debugger.h"
|
|
|
|
//#define LOG_DEV_CALLS(x) printf x
|
|
#define LOG_DEV_CALLS(x) do { } while (0)
|
|
|
|
const device_type NETLIST_CORE = &device_creator<netlist_mame_device_t>;
|
|
const device_type NETLIST_CPU = &device_creator<netlist_mame_cpu_device_t>;
|
|
const device_type NETLIST_SOUND = &device_creator<netlist_mame_sound_device_t>;
|
|
|
|
/* subdevices */
|
|
|
|
const device_type NETLIST_ANALOG_INPUT = &device_creator<netlist_mame_analog_input_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>;
|
|
|
|
const device_type NETLIST_ANALOG_OUTPUT = &device_creator<netlist_mame_analog_output_t>;
|
|
const device_type NETLIST_STREAM_OUTPUT = &device_creator<netlist_mame_stream_output_t>;
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// netlist_mame_analog_input_t
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
void netlist_mame_sub_interface::static_set_mult_offset(device_t &device, const double mult, const double offset)
|
|
{
|
|
netlist_mame_sub_interface &netlist = dynamic_cast<netlist_mame_sub_interface &>(device);
|
|
netlist.m_mult = mult;
|
|
netlist.m_offset = offset;
|
|
}
|
|
|
|
|
|
netlist_mame_analog_input_t::netlist_mame_analog_input_t(const machine_config &mconfig, std::string tag, device_t *owner, UINT32 clock)
|
|
: device_t(mconfig, NETLIST_ANALOG_INPUT, "Netlist Analog Input", tag, owner, clock, "netlist_analog_input", __FILE__),
|
|
netlist_mame_sub_interface(*owner),
|
|
m_param(nullptr),
|
|
m_auto_port(true),
|
|
m_param_name("")
|
|
{
|
|
}
|
|
|
|
void netlist_mame_analog_input_t::static_set_name(device_t &device, const char *param_name)
|
|
{
|
|
netlist_mame_analog_input_t &netlist = downcast<netlist_mame_analog_input_t &>(device);
|
|
netlist.m_param_name = param_name;
|
|
}
|
|
|
|
void netlist_mame_analog_input_t::device_start()
|
|
{
|
|
LOG_DEV_CALLS(("start %s\n", tag().c_str()));
|
|
netlist::param_t *p = this->nl_owner().setup().find_param(m_param_name);
|
|
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.cstr());
|
|
}
|
|
if (m_mult != 1.0 || m_offset != 0.0)
|
|
{
|
|
// disable automatic scaling for ioports
|
|
m_auto_port = false;
|
|
}
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// netlist_mame_analog_output_t
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
netlist_mame_analog_output_t::netlist_mame_analog_output_t(const machine_config &mconfig, std::string tag, device_t *owner, UINT32 clock)
|
|
: device_t(mconfig, NETLIST_ANALOG_INPUT, "Netlist Analog Output", tag, owner, clock, "netlist_analog_output", __FILE__),
|
|
netlist_mame_sub_interface(*owner),
|
|
m_in("")
|
|
{
|
|
}
|
|
|
|
void netlist_mame_analog_output_t::static_set_params(device_t &device, const char *in_name, netlist_analog_output_delegate adelegate)
|
|
{
|
|
netlist_mame_analog_output_t &netlist = downcast<netlist_mame_analog_output_t &>(device);
|
|
netlist.m_in = in_name;
|
|
netlist.m_delegate = adelegate;
|
|
}
|
|
|
|
void netlist_mame_analog_output_t::custom_netlist_additions(netlist::setup_t &setup)
|
|
{
|
|
pstring dname = "OUT_" + m_in;
|
|
m_delegate.bind_relative_to(owner()->machine().root_device());
|
|
NETLIB_NAME(analog_callback) *dev = downcast<NETLIB_NAME(analog_callback) *>(
|
|
setup.register_dev("NETDEV_CALLBACK", dname));
|
|
|
|
dev->register_callback(m_delegate);
|
|
setup.register_link(dname + ".IN", m_in);
|
|
}
|
|
|
|
void netlist_mame_analog_output_t::device_start()
|
|
{
|
|
LOG_DEV_CALLS(("start %s\n", tag().c_str()));
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// netlist_mame_logic_input_t
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
netlist_mame_logic_input_t::netlist_mame_logic_input_t(const machine_config &mconfig, std::string tag, device_t *owner, UINT32 clock)
|
|
: device_t(mconfig, NETLIST_ANALOG_INPUT, "Netlist Logic Input", tag, owner, clock, "netlist_logic_input", __FILE__),
|
|
netlist_mame_sub_interface(*owner),
|
|
m_param(nullptr),
|
|
m_mask(0xffffffff),
|
|
m_shift(0),
|
|
m_param_name("")
|
|
{
|
|
}
|
|
|
|
void netlist_mame_logic_input_t::static_set_params(device_t &device, const char *param_name, const UINT32 mask, const UINT32 shift)
|
|
{
|
|
netlist_mame_logic_input_t &netlist = downcast<netlist_mame_logic_input_t &>(device);
|
|
LOG_DEV_CALLS(("static_set_params %s\n", device.tag()));
|
|
netlist.m_param_name = param_name;
|
|
netlist.m_shift = shift;
|
|
netlist.m_mask = mask;
|
|
}
|
|
|
|
void netlist_mame_logic_input_t::device_start()
|
|
{
|
|
LOG_DEV_CALLS(("start %s\n", tag().c_str()));
|
|
netlist::param_t *p = downcast<netlist_mame_device_t *>(this->owner())->setup().find_param(m_param_name);
|
|
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.cstr());
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// netlist_mame_stream_input_t
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
netlist_mame_stream_input_t::netlist_mame_stream_input_t(const machine_config &mconfig, std::string tag, device_t *owner, UINT32 clock)
|
|
: device_t(mconfig, NETLIST_ANALOG_INPUT, "Netlist Stream Input", tag, owner, clock, "netlist_stream_input", __FILE__),
|
|
netlist_mame_sub_interface(*owner),
|
|
m_channel(0),
|
|
m_param_name("")
|
|
{
|
|
}
|
|
|
|
void netlist_mame_stream_input_t::static_set_params(device_t &device, int channel, const char *param_name)
|
|
{
|
|
netlist_mame_stream_input_t &netlist = downcast<netlist_mame_stream_input_t &>(device);
|
|
netlist.m_param_name = param_name;
|
|
netlist.m_channel = channel;
|
|
}
|
|
|
|
void netlist_mame_stream_input_t::device_start()
|
|
{
|
|
LOG_DEV_CALLS(("start %s\n", tag().c_str()));
|
|
}
|
|
|
|
void netlist_mame_stream_input_t::custom_netlist_additions(netlist::setup_t &setup)
|
|
{
|
|
NETLIB_NAME(sound_in) *snd_in = setup.netlist().get_first_device<NETLIB_NAME(sound_in)>();
|
|
if (snd_in == nullptr)
|
|
snd_in = dynamic_cast<NETLIB_NAME(sound_in) *>(setup.register_dev("NETDEV_SOUND_IN", "STREAM_INPUT"));
|
|
|
|
pstring sparam = pfmt("STREAM_INPUT.CHAN{1}")(m_channel);
|
|
setup.register_param(sparam, m_param_name);
|
|
sparam = pfmt("STREAM_INPUT.MULT{1}")(m_channel);
|
|
setup.register_param(sparam, m_mult);
|
|
sparam = pfmt("STREAM_INPUT.OFFSET{1}")(m_channel);
|
|
setup.register_param(sparam, m_offset);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// netlist_mame_stream_output_t
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
netlist_mame_stream_output_t::netlist_mame_stream_output_t(const machine_config &mconfig, std::string tag, device_t *owner, UINT32 clock)
|
|
: device_t(mconfig, NETLIST_ANALOG_INPUT, "Netlist Stream Output", tag, owner, clock, "netlist_stream_output", __FILE__),
|
|
netlist_mame_sub_interface(*owner),
|
|
m_channel(0),
|
|
m_out_name("")
|
|
{
|
|
}
|
|
|
|
void netlist_mame_stream_output_t::static_set_params(device_t &device, int channel, const char *out_name)
|
|
{
|
|
netlist_mame_stream_output_t &netlist = downcast<netlist_mame_stream_output_t &>(device);
|
|
netlist.m_out_name = out_name;
|
|
netlist.m_channel = channel;
|
|
}
|
|
|
|
void netlist_mame_stream_output_t::device_start()
|
|
{
|
|
LOG_DEV_CALLS(("start %s\n", tag().c_str()));
|
|
}
|
|
|
|
void netlist_mame_stream_output_t::custom_netlist_additions(netlist::setup_t &setup)
|
|
{
|
|
//NETLIB_NAME(sound_out) *snd_out;
|
|
pstring sname = pfmt("STREAM_OUT_{1}")(m_channel);
|
|
|
|
//snd_out = dynamic_cast<NETLIB_NAME(sound_out) *>(setup.register_dev("nld_sound_out", sname));
|
|
setup.register_dev("NETDEV_SOUND_OUT", sname);
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// netlist_mame_t
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
void netlist_mame_t::vlog(const plog_level &l, const pstring &ls) const
|
|
{
|
|
pstring errstr = ls;
|
|
|
|
switch (l)
|
|
{
|
|
case plog_level::DEBUG:
|
|
m_parent.logerror("netlist DEBUG: %s\n", errstr.cstr());
|
|
break;
|
|
case plog_level::INFO:
|
|
m_parent.logerror("netlist INFO: %s\n", errstr.cstr());
|
|
break;
|
|
case plog_level::VERBOSE:
|
|
m_parent.logerror("netlist VERBOSE: %s\n", errstr.cstr());
|
|
break;
|
|
case plog_level::WARNING:
|
|
m_parent.logerror("netlist WARNING: %s\n", errstr.cstr());
|
|
break;
|
|
case plog_level::ERROR:
|
|
m_parent.logerror("netlist ERROR: %s\n", errstr.cstr());
|
|
break;
|
|
case plog_level::FATAL:
|
|
emu_fatalerror error("netlist ERROR: %s\n", errstr.cstr());
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// 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, std::string tag, device_t *owner, UINT32 clock)
|
|
: device_t(mconfig, NETLIST_CORE, "Netlist core device", tag, owner, clock, "netlist_core", __FILE__),
|
|
m_icount(0),
|
|
m_old(netlist::netlist_time::zero),
|
|
m_netlist(nullptr),
|
|
m_setup(nullptr),
|
|
m_setup_func(nullptr)
|
|
{
|
|
}
|
|
|
|
netlist_mame_device_t::netlist_mame_device_t(const machine_config &mconfig, device_type type, const char *name, std::string tag, device_t *owner, UINT32 clock, const char *shortname, const char *file)
|
|
: device_t(mconfig, type, name, tag, owner, clock, shortname, file),
|
|
m_icount(0),
|
|
m_old(netlist::netlist_time::zero),
|
|
m_netlist(nullptr),
|
|
m_setup(nullptr),
|
|
m_setup_func(nullptr)
|
|
{
|
|
}
|
|
|
|
void netlist_mame_device_t::static_set_constructor(device_t &device, void (*setup_func)(netlist::setup_t &))
|
|
{
|
|
LOG_DEV_CALLS(("static_set_constructor\n"));
|
|
netlist_mame_device_t &netlist = downcast<netlist_mame_device_t &>(device);
|
|
netlist.m_setup_func = setup_func;
|
|
}
|
|
|
|
void netlist_mame_device_t::device_config_complete()
|
|
{
|
|
LOG_DEV_CALLS(("device_config_complete\n"));
|
|
}
|
|
|
|
void netlist_mame_device_t::device_start()
|
|
{
|
|
LOG_DEV_CALLS(("device_start %s\n", tag().c_str()));
|
|
|
|
//printf("clock is %d\n", clock());
|
|
|
|
m_netlist = global_alloc(netlist_mame_t(*this));
|
|
m_setup = global_alloc(netlist::setup_t(m_netlist));
|
|
netlist().init_object(*m_netlist, "netlist");
|
|
m_setup->init();
|
|
|
|
// register additional devices
|
|
|
|
nl_register_devices();
|
|
|
|
m_setup_func(*m_setup);
|
|
|
|
/* let sub-devices tweak the netlist */
|
|
for( device_t *d = this->first_subdevice(); d != nullptr; d = d->next() )
|
|
{
|
|
netlist_mame_sub_interface *sdev = dynamic_cast<netlist_mame_sub_interface *>(d);
|
|
if( sdev != nullptr )
|
|
{
|
|
LOG_DEV_CALLS(("Found subdevice %s/%s\n", d->name(), d->shortname()));
|
|
sdev->custom_netlist_additions(*m_setup);
|
|
}
|
|
}
|
|
|
|
m_setup->start_devices();
|
|
m_setup->resolve_inputs();
|
|
|
|
netlist().save(NAME(m_rem));
|
|
netlist().save(NAME(m_div));
|
|
netlist().save(NAME(m_old));
|
|
|
|
save_state();
|
|
|
|
m_old = netlist::netlist_time::zero;
|
|
m_rem = netlist::netlist_time::zero;
|
|
|
|
}
|
|
|
|
void netlist_mame_device_t::device_clock_changed()
|
|
{
|
|
m_div = netlist::netlist_time::from_hz(clock());
|
|
netlist().log().debug("Setting clock {1} and divisor {2}\n", clock(), m_div.as_double());
|
|
}
|
|
|
|
|
|
void netlist_mame_device_t::device_reset()
|
|
{
|
|
LOG_DEV_CALLS(("device_reset\n"));
|
|
m_old = netlist::netlist_time::zero;
|
|
m_rem = netlist::netlist_time::zero;
|
|
netlist().do_reset();
|
|
}
|
|
|
|
void netlist_mame_device_t::device_stop()
|
|
{
|
|
LOG_DEV_CALLS(("device_stop\n"));
|
|
m_setup->print_stats();
|
|
|
|
m_netlist->stop();
|
|
|
|
global_free(m_setup);
|
|
m_setup = nullptr;
|
|
global_free(m_netlist);
|
|
m_netlist = nullptr;
|
|
}
|
|
|
|
ATTR_COLD void netlist_mame_device_t::device_post_load()
|
|
{
|
|
LOG_DEV_CALLS(("device_post_load\n"));
|
|
|
|
netlist().post_load();
|
|
netlist().rebuild_lists();
|
|
}
|
|
|
|
ATTR_COLD void netlist_mame_device_t::device_pre_save()
|
|
{
|
|
LOG_DEV_CALLS(("device_pre_save\n"));
|
|
|
|
netlist().pre_save();
|
|
}
|
|
|
|
void netlist_mame_device_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
|
{
|
|
}
|
|
|
|
ATTR_HOT ATTR_ALIGN void netlist_mame_device_t::update_time_x()
|
|
{
|
|
const netlist::netlist_time newt = netlist().time();
|
|
const netlist::netlist_time delta = newt - m_old + m_rem;
|
|
const UINT64 d = delta / m_div;
|
|
m_old = newt;
|
|
m_rem = delta - (m_div * d);
|
|
m_icount -= d;
|
|
}
|
|
|
|
ATTR_HOT ATTR_ALIGN void netlist_mame_device_t::check_mame_abort_slice()
|
|
{
|
|
if (m_icount <= 0)
|
|
netlist().abort_current_queue_slice();
|
|
}
|
|
|
|
ATTR_COLD void netlist_mame_device_t::save_state()
|
|
{
|
|
for (int i=0; i< netlist().save_list().size(); i++)
|
|
{
|
|
pstate_entry_t *s = netlist().save_list()[i];
|
|
netlist().log().debug("saving state for {1}\n", s->m_name.cstr());
|
|
switch (s->m_dt)
|
|
{
|
|
case DT_DOUBLE:
|
|
{
|
|
double *td = s->resolved<double>();
|
|
if (td != nullptr) save_pointer(td, s->m_name.cstr(), s->m_count);
|
|
}
|
|
break;
|
|
case DT_FLOAT:
|
|
{
|
|
float *td = s->resolved<float>();
|
|
if (td != nullptr) save_pointer(td, s->m_name.cstr(), s->m_count);
|
|
}
|
|
break;
|
|
#if (PHAS_INT128)
|
|
case DT_INT128:
|
|
// FIXME: we are cheating here
|
|
save_pointer((char *) s->m_ptr, s->m_name.cstr(), s->m_count * sizeof(INT128));
|
|
break;
|
|
#endif
|
|
case DT_INT64:
|
|
save_pointer((INT64 *) s->m_ptr, s->m_name.cstr(), s->m_count);
|
|
break;
|
|
case DT_INT16:
|
|
save_pointer((INT16 *) s->m_ptr, s->m_name.cstr(), s->m_count);
|
|
break;
|
|
case DT_INT8:
|
|
save_pointer((INT8 *) s->m_ptr, s->m_name.cstr(), s->m_count);
|
|
break;
|
|
case DT_INT:
|
|
save_pointer((int *) s->m_ptr, s->m_name.cstr(), s->m_count);
|
|
break;
|
|
case DT_BOOLEAN:
|
|
save_pointer((bool *) s->m_ptr, s->m_name.cstr(), s->m_count);
|
|
break;
|
|
case DT_CUSTOM:
|
|
break;
|
|
case NOT_SUPPORTED:
|
|
default:
|
|
netlist().log().fatal("found unsupported save element %s\n", s->m_name);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// netlist_mame_cpu_device_t
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
netlist_mame_cpu_device_t::netlist_mame_cpu_device_t(const machine_config &mconfig, std::string tag, device_t *owner, UINT32 clock)
|
|
: netlist_mame_device_t(mconfig, NETLIST_CPU, "Netlist CPU Device", tag, owner, clock, "netlist_cpu", __FILE__),
|
|
device_execute_interface(mconfig, *this),
|
|
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))
|
|
{
|
|
}
|
|
|
|
|
|
void netlist_mame_cpu_device_t::device_start()
|
|
{
|
|
netlist_mame_device_t::device_start();
|
|
|
|
LOG_DEV_CALLS(("cpu device_start %s\n", tag().c_str()));
|
|
|
|
// State support
|
|
|
|
state_add(STATE_GENPC, "curpc", m_genPC).noshow();
|
|
|
|
for (int i=0; i < netlist().m_nets.size(); i++)
|
|
{
|
|
netlist::net_t *n = netlist().m_nets[i];
|
|
if (n->isFamily(netlist::object_t::LOGIC))
|
|
{
|
|
state_add(i*2, n->name().cstr(), downcast<netlist::logic_net_t *>(n)->Q_state_ptr());
|
|
}
|
|
else
|
|
{
|
|
state_add(i*2+1, n->name().cstr(), downcast<netlist::analog_net_t *>(n)->Q_Analog_state_ptr()).formatstr("%20s");
|
|
}
|
|
}
|
|
|
|
// set our instruction counter
|
|
m_icountptr = &m_icount;
|
|
}
|
|
|
|
|
|
void netlist_mame_cpu_device_t::nl_register_devices()
|
|
{
|
|
setup().factory().register_device<nld_analog_callback>( "NETDEV_CALLBACK", "nld_analog_callback", "-");
|
|
}
|
|
|
|
ATTR_COLD UINT64 netlist_mame_cpu_device_t::execute_clocks_to_cycles(UINT64 clocks) const
|
|
{
|
|
return clocks;
|
|
}
|
|
|
|
ATTR_COLD UINT64 netlist_mame_cpu_device_t::execute_cycles_to_clocks(UINT64 cycles) const
|
|
{
|
|
return cycles;
|
|
}
|
|
|
|
ATTR_COLD offs_t netlist_mame_cpu_device_t::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
|
|
{
|
|
//char tmp[16];
|
|
unsigned startpc = pc;
|
|
int relpc = pc - m_genPC;
|
|
if (relpc >= 0 && relpc < netlist().queue().count())
|
|
{
|
|
int dpc = netlist().queue().count() - relpc - 1;
|
|
// FIXME: 50 below fixes crash in mame-debugger. It's based on try on error.
|
|
snprintf(buffer, 50, "%c %s @%10.7f", (relpc == 0) ? '*' : ' ', netlist().queue()[dpc].object()->name().cstr(),
|
|
netlist().queue()[dpc].exec_time().as_double());
|
|
}
|
|
else
|
|
sprintf(buffer, "%s", "");
|
|
|
|
pc+=1;
|
|
return (pc - startpc);
|
|
}
|
|
|
|
ATTR_HOT void netlist_mame_cpu_device_t::execute_run()
|
|
{
|
|
bool check_debugger = ((device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) != 0);
|
|
// debugging
|
|
//m_ppc = m_pc; // copy PC to previous PC
|
|
if (check_debugger)
|
|
{
|
|
while (m_icount > 0)
|
|
{
|
|
m_genPC++;
|
|
m_genPC &= 255;
|
|
debugger_instruction_hook(this, m_genPC);
|
|
netlist().process_queue(m_div);
|
|
update_time_x();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
netlist().process_queue(m_div * m_icount);
|
|
update_time_x();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// netlist_mame_sound_device_t
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
netlist_mame_sound_device_t::netlist_mame_sound_device_t(const machine_config &mconfig, std::string tag, device_t *owner, UINT32 clock)
|
|
: netlist_mame_device_t(mconfig, NETLIST_CPU, "Netlist Sound Device", tag, owner, clock, "netlist_sound", __FILE__),
|
|
device_sound_interface(mconfig, *this)
|
|
{
|
|
}
|
|
|
|
void netlist_mame_sound_device_t::device_start()
|
|
{
|
|
netlist_mame_device_t::device_start();
|
|
|
|
LOG_DEV_CALLS(("sound device_start %s\n", tag().c_str()));
|
|
|
|
// Configure outputs
|
|
|
|
plist_t<nld_sound_out *> outdevs = netlist().get_device_list<nld_sound_out>();
|
|
if (outdevs.size() == 0)
|
|
fatalerror("No output devices");
|
|
|
|
m_num_outputs = outdevs.size();
|
|
|
|
/* resort channels */
|
|
for (int i=0; i < MAX_OUT; i++) m_out[i] = nullptr;
|
|
for (int i=0; i < m_num_outputs; i++)
|
|
{
|
|
int chan = outdevs[i]->m_channel.Value();
|
|
|
|
netlist().log().verbose("Output %d on channel %d", i, chan);
|
|
|
|
if (chan < 0 || chan >= MAX_OUT || chan >= outdevs.size())
|
|
fatalerror("illegal channel number");
|
|
m_out[chan] = outdevs[i];
|
|
m_out[chan]->m_sample = netlist::netlist_time::from_hz(clock());
|
|
m_out[chan]->m_buffer = nullptr;
|
|
}
|
|
|
|
// Configure inputs
|
|
|
|
m_num_inputs = 0;
|
|
m_in = nullptr;
|
|
|
|
plist_t<nld_sound_in *> indevs = netlist().get_device_list<nld_sound_in>();
|
|
if (indevs.size() > 1)
|
|
fatalerror("A maximum of one input device is allowed!");
|
|
if (indevs.size() == 1)
|
|
{
|
|
m_in = indevs[0];
|
|
m_num_inputs = m_in->resolve();
|
|
m_in->m_inc = netlist::netlist_time::from_hz(clock());
|
|
}
|
|
|
|
/* initialize the stream(s) */
|
|
m_stream = machine().sound().stream_alloc(*this, m_num_inputs, m_num_outputs, clock());
|
|
|
|
}
|
|
|
|
void netlist_mame_sound_device_t::nl_register_devices()
|
|
{
|
|
setup().factory().register_device<nld_sound_out>("NETDEV_SOUND_OUT", "nld_sound_out", "+CHAN");
|
|
setup().factory().register_device<nld_sound_in>("NETDEV_SOUND_IN", "nld_sound_in", "-");
|
|
}
|
|
|
|
|
|
void netlist_mame_sound_device_t::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
|
|
{
|
|
for (int i=0; i < m_num_outputs; i++)
|
|
{
|
|
m_out[i]->m_buffer = outputs[i];
|
|
}
|
|
|
|
if (m_num_inputs)
|
|
m_in->buffer_reset();
|
|
|
|
for (int i=0; i < m_num_inputs; i++)
|
|
{
|
|
m_in->m_buffer[i] = inputs[i];
|
|
}
|
|
|
|
netlist::netlist_time cur = netlist().time();
|
|
|
|
netlist().process_queue(m_div * samples);
|
|
|
|
cur += (m_div * samples);
|
|
|
|
for (int i=0; i < m_num_outputs; i++)
|
|
{
|
|
m_out[i]->sound_update(cur);
|
|
m_out[i]->buffer_reset(cur);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// memregion source support
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
bool netlist_source_memregion_t::parse(netlist::setup_t &setup, const pstring &name)
|
|
{
|
|
// FIXME: preprocessor should be a stream!
|
|
memory_region *mem = downcast<netlist_mame_t &>(setup.netlist()).machine().root_device().memregion(m_name.cstr());
|
|
pimemstream istrm(mem->base(),mem->bytes() );
|
|
pomemstream ostrm;
|
|
|
|
pimemstream istrm2(ppreprocessor().process(istrm, ostrm));
|
|
return netlist::parser_t(istrm2, setup).parse(name);
|
|
}
|