summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/devices/machine/netlist.cpp83
-rw-r--r--src/devices/machine/netlist.h24
-rw-r--r--src/devices/machine/pit8253.cpp78
-rw-r--r--src/devices/machine/pit8253.h20
-rw-r--r--src/devices/sound/sp0250.cpp234
-rw-r--r--src/devices/sound/sp0250.h58
-rw-r--r--src/lib/netlist/devices/nld_4020.cpp20
-rw-r--r--src/lib/netlist/devices/nld_4053.cpp70
-rw-r--r--src/lib/netlist/devices/nld_devinc.h12
-rw-r--r--src/lib/netlist/macro/nlm_opamp_lib.cpp9
-rw-r--r--src/lib/netlist/macro/nlm_opamp_lib.h3
-rw-r--r--src/lib/netlist/macro/nlm_ttl74xx_lib.cpp57
-rw-r--r--src/lib/netlist/macro/nlm_ttl74xx_lib.h3
-rw-r--r--src/lib/netlist/nl_errstr.h4
-rw-r--r--src/lib/netlist/nl_setup.cpp9
-rw-r--r--src/mame/audio/nl_astrob.cpp1161
-rw-r--r--src/mame/audio/nl_astrob.h10
-rw-r--r--src/mame/audio/nl_cinemat_common.h2
-rw-r--r--src/mame/audio/nl_elim.cpp1225
-rw-r--r--src/mame/audio/nl_elim.h11
-rw-r--r--src/mame/audio/nl_segaspeech.cpp119
-rw-r--r--src/mame/audio/nl_segaspeech.h10
-rw-r--r--src/mame/audio/nl_segausb.cpp544
-rw-r--r--src/mame/audio/nl_segausb.h10
-rw-r--r--src/mame/audio/nl_spacfury.cpp1105
-rw-r--r--src/mame/audio/nl_spacfury.h10
-rw-r--r--src/mame/audio/segag80.cpp185
-rw-r--r--src/mame/audio/segag80.h74
-rw-r--r--src/mame/audio/segag80r.cpp254
-rw-r--r--src/mame/audio/segag80v.cpp327
-rw-r--r--src/mame/audio/segasnd.cpp909
-rw-r--r--src/mame/audio/segasnd.h214
-rw-r--r--src/mame/audio/segaspeech.cpp217
-rw-r--r--src/mame/audio/segaspeech.h61
-rw-r--r--src/mame/audio/segausb.cpp859
-rw-r--r--src/mame/audio/segausb.h192
-rw-r--r--src/mame/drivers/segag80r.cpp130
-rw-r--r--src/mame/drivers/segag80v.cpp636
-rw-r--r--src/mame/drivers/zaxxon.cpp2
-rw-r--r--src/mame/includes/segag80r.h17
-rw-r--r--src/mame/includes/segag80v.h137
-rw-r--r--src/mame/nl.lst43
-rw-r--r--src/mame/video/segag80v.cpp316
43 files changed, 7033 insertions, 2431 deletions
diff --git a/src/devices/machine/netlist.cpp b/src/devices/machine/netlist.cpp
index 8dd06070960..3af1570edb5 100644
--- a/src/devices/machine/netlist.cpp
+++ b/src/devices/machine/netlist.cpp
@@ -366,6 +366,9 @@ void netlist_mame_analog_input_device::write(const double val)
void netlist_mame_analog_input_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
update_to_current_time();
+#if NETLIST_CREATE_CSV
+ nl_owner().log_add(m_param_name, *((double *) ptr), true);
+#endif
m_param->set(*((double *) ptr));
}
@@ -392,12 +395,18 @@ void netlist_mame_logic_input_device::write(const uint32_t val)
void netlist_mame_int_input_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
update_to_current_time();
+#if NETLIST_CREATE_CSV
+ nl_owner().log_add(m_param_name, param, false);
+#endif
m_param->set(param);
}
void netlist_mame_logic_input_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
update_to_current_time();
+#if NETLIST_CREATE_CSV
+ nl_owner().log_add(m_param_name, param, false);
+#endif
m_param->set(param);
}
@@ -435,6 +444,57 @@ void netlist_mame_sub_interface::set_mult_offset(const double mult, const double
m_offset = offset;
}
+#if NETLIST_CREATE_CSV
+void netlist_mame_device::log_add(char const* param, double value, bool isfloat)
+{
+ // skip if no file
+ if (m_csv_file == nullptr)
+ return;
+
+ // make a new entry
+ buffer_entry entry = { machine().scheduler().time(), isfloat, value, param };
+
+ // flush out half of the old entries if we hit the buffer limit
+ if (m_buffer.size() >= MAX_BUFFER_ENTRIES)
+ log_flush(MAX_BUFFER_ENTRIES / 2);
+
+ // fast common case: if we go at the end, just push_back
+ if (m_buffer.size() == 0 || entry.time >= m_buffer.back().time)
+ {
+ m_buffer.push_back(entry);
+ return;
+ }
+
+ // find our place in the queue
+ for (auto cur = m_buffer.rbegin(); cur != m_buffer.rend(); cur++)
+ if (entry.time >= cur->time)
+ {
+ m_buffer.insert(cur.base(), entry);
+ return;
+ }
+
+ // if we're too early, drop this entry rather than risk putting an out-of-order
+ // entry after the last one we flushed
+}
+
+void netlist_mame_device::log_flush(int count)
+{
+ if (m_csv_file == nullptr)
+ return;
+ if (count > m_buffer.size())
+ count = m_buffer.size();
+ while (count--)
+ {
+ auto &entry = m_buffer.front();
+ if (entry.isfloat)
+ fprintf(m_csv_file, "%s,%s,%f\n", entry.time.as_string(), entry.string, entry.value);
+ else
+ fprintf(m_csv_file, "%s,%s,%d\n", entry.time.as_string(), entry.string, int(entry.value));
+ m_buffer.pop_front();
+ }
+}
+#endif
+
netlist_mame_analog_input_device::netlist_mame_analog_input_device(const machine_config &mconfig, const char *tag, device_t *owner, const char *param_name)
: device_t(mconfig, NETLIST_ANALOG_INPUT, tag, owner, 0)
, netlist_mame_sub_interface(*owner)
@@ -833,7 +893,7 @@ void netlist_mame_stream_output_device::device_reset()
void netlist_mame_stream_output_device::sound_update_fill(std::size_t samples, stream_sample_t *target)
{
if (samples < m_buffer.size())
- throw emu_fatalerror("sound %s: samples %d less bufsize %d\n", name(), samples, m_buffer.size());
+ osd_printf_warning("sound %s: samples %d less bufsize %d\n", name(), samples, m_buffer.size());
std::copy(m_buffer.begin(), m_buffer.end(), target);
std::size_t pos = m_buffer.size();
@@ -1036,6 +1096,18 @@ void netlist_mame_device::device_start_common()
m_device_reset_called = false;
+
+#if NETLIST_CREATE_CSV
+ std::string name = machine().system().name;
+ name += tag();
+ for (int index = 0; index < name.size(); index++)
+ if (name[index] == ':')
+ name[index] = '_';
+ name += ".csv";
+ m_csv_file = fopen(name.c_str(), "wb");
+#endif
+
+ LOGDEVCALLS("device_start exit\n");
}
@@ -1070,7 +1142,14 @@ void netlist_mame_device::device_stop()
{
LOGDEVCALLS("device_stop\n");
if (m_netlist)
- m_netlist->exec().stop();
+ netlist().exec().stop();
+#if NETLIST_CREATE_CSV
+ if (m_csv_file != nullptr)
+ {
+ log_flush();
+ fclose(m_csv_file);
+ }
+#endif
}
void netlist_mame_device::device_post_load()
diff --git a/src/devices/machine/netlist.h b/src/devices/machine/netlist.h
index b7bd668cc32..8b35b13bacf 100644
--- a/src/devices/machine/netlist.h
+++ b/src/devices/machine/netlist.h
@@ -12,9 +12,14 @@
#define MAME_MACHINE_NETLIST_H
#include <functional>
+#include <deque>
#include "../../lib/netlist/nltypes.h"
+#ifndef NETLIST_CREATE_CSV
+#define NETLIST_CREATE_CSV (0)
+#endif
+
class netlist_mame_stream_output_device;
class nld_sound_in;
@@ -106,6 +111,25 @@ private:
func_type m_setup_func;
bool m_device_reset_called;
+
+#if NETLIST_CREATE_CSV
+ static constexpr int MAX_BUFFER_ENTRIES = 1000;
+
+public:
+ void log_add(char const* param, double value, bool isfloat);
+ void log_flush(int count = MAX_BUFFER_ENTRIES);
+
+private:
+ struct buffer_entry
+ {
+ attotime time;
+ bool isfloat;
+ double value;
+ char const *string;
+ };
+ std::deque<buffer_entry> m_buffer;
+ FILE* m_csv_file = nullptr;
+#endif
};
class netlist_mame_cpu_device : public netlist_mame_device,
diff --git a/src/devices/machine/pit8253.cpp b/src/devices/machine/pit8253.cpp
index eecffb58b9e..2e73aecbcb9 100644
--- a/src/devices/machine/pit8253.cpp
+++ b/src/devices/machine/pit8253.cpp
@@ -101,6 +101,7 @@ void pit8253_device::device_resolve_objects()
m_out_handler[timer].resolve_safe();
m_counter[timer]->m_index = timer;
m_counter[timer]->m_clockin = m_clk[timer];
+ m_counter[timer]->m_clock_period = (m_clk[timer] != 0) ? attotime::from_hz(m_clk[timer]) : attotime::never;
}
}
@@ -112,11 +113,12 @@ void pit8253_device::device_resolve_objects()
void pit_counter_device::device_start()
{
/* initialize timer */
- m_updatetimer = timer_alloc();
- m_updatetimer->adjust(attotime::never);
+ m_updatetimer = timer_alloc(TID_UPDATE);
+ adjust_timer(attotime::never);
/* set up state save values */
save_item(NAME(m_clockin));
+ save_item(NAME(m_clock_period));
save_item(NAME(m_control));
save_item(NAME(m_status));
save_item(NAME(m_lowcount));
@@ -197,6 +199,14 @@ void pit_counter_device::device_reset()
#define CTRL_MODE(control) (((control) >> 1) & (((control) & 0x04) ? 0x03 : 0x07))
#define CTRL_BCD(control) (((control) >> 0) & 0x01)
+inline void pit_counter_device::adjust_timer(attotime target)
+{
+// if (target != m_next_update)
+ {
+ m_next_update = target;
+ m_updatetimer->adjust(target - machine().time());
+ }
+}
inline uint32_t pit_counter_device::adjusted_count() const
{
@@ -684,15 +694,9 @@ void pit_counter_device::simulate(int64_t elapsed_cycles)
}
if (cycles_to_output == CYCLES_NEVER || m_clockin == 0)
- {
- m_updatetimer->adjust(attotime::never);
- }
+ adjust_timer(attotime::never);
else
- {
- attotime next_fire_time = m_last_updated + cycles_to_output * attotime::from_hz(m_clockin);
-
- m_updatetimer->adjust(next_fire_time - machine().time());
- }
+ adjust_timer(m_last_updated + cycles_to_output * m_clock_period);
LOG2("simulate(): simulating %d cycles in mode %d, bcd = %d, phase = %d, gate = %d, output %d, value = 0x%04x, cycles_to_output = %04x\n",
(int)elapsed_cycles, mode, bcd, m_phase, m_gate, m_output, m_value, cycles_to_output);
@@ -704,13 +708,19 @@ void pit_counter_device::update()
/* With the 82C54's maximum clockin of 10MHz, 64 bits is nearly 60,000
years of time. Should be enough for now. */
attotime now = machine().time();
- attotime elapsed_time = now - m_last_updated;
- int64_t elapsed_cycles = elapsed_time.as_double() * m_clockin;
+ int64_t elapsed_cycles = 0;
+ if (m_clockin != 0)
+ {
+ if (now > m_last_updated)
+ {
+ attotime elapsed_time = now - m_last_updated;
+ elapsed_cycles = elapsed_time.as_double() * m_clockin;
- LOG2("update(): %d elapsed_cycles\n", elapsed_cycles);
+ LOG2("update(): %d elapsed_cycles\n", elapsed_cycles);
- if (m_clockin)
- m_last_updated += elapsed_cycles * attotime::from_hz(m_clockin);
+ m_last_updated += elapsed_cycles * m_clock_period;
+ }
+ }
else
m_last_updated = now;
@@ -718,8 +728,8 @@ void pit_counter_device::update()
sections punctuated by callbacks. */
if (elapsed_cycles > 0)
simulate(elapsed_cycles);
- else if (m_clockin)
- m_updatetimer->adjust(attotime::from_hz(m_clockin));
+ else if (m_clockin != 0)
+ adjust_timer(m_last_updated + m_clock_period);
}
@@ -928,12 +938,27 @@ void pit8254_device::readback_command(uint8_t data)
void pit_counter_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
update();
+ switch (id)
+ {
+ case TID_UPDATE:
+ break;
+
+ case TID_CONTROL:
+ control_w_deferred(param);
+ break;
+
+ case TID_COUNT:
+ count_w_deferred(param);
+ break;
+
+ case TID_GATE:
+ gate_w_deferred(param);
+ break;
+ }
}
-void pit_counter_device::control_w(uint8_t data)
+void pit_counter_device::control_w_deferred(uint8_t data)
{
- update();
-
if (CTRL_ACCESS(data) == 0)
{
LOG1("write(): readback\n");
@@ -955,10 +980,8 @@ void pit_counter_device::control_w(uint8_t data)
}
}
-void pit_counter_device::count_w(uint8_t data)
+void pit_counter_device::count_w_deferred(uint8_t data)
{
- update();
-
bool middle_of_a_cycle = (machine().time() > m_last_updated && m_clockin != 0);
switch (CTRL_ACCESS(m_control))
@@ -972,7 +995,7 @@ void pit_counter_device::count_w(uint8_t data)
/* check if we should compensate for not being on a cycle boundary */
if (middle_of_a_cycle)
- m_last_updated += attotime::from_hz(m_clockin);
+ m_last_updated += m_clock_period;
load_count(data);
simulate(0);
@@ -986,7 +1009,7 @@ void pit_counter_device::count_w(uint8_t data)
/* check if we should compensate for not being on a cycle boundary */
if (middle_of_a_cycle)
- m_last_updated += attotime::from_hz(m_clockin);
+ m_last_updated += m_clock_period;
load_count(data << 8);
simulate(0);
@@ -1001,7 +1024,7 @@ void pit_counter_device::count_w(uint8_t data)
{
/* check if we should compensate for not being on a cycle boundary */
if (middle_of_a_cycle)
- m_last_updated += attotime::from_hz(m_clockin);
+ m_last_updated += m_clock_period;
load_count(m_lowcount | (data << 8));
simulate(0);
@@ -1042,7 +1065,7 @@ void pit8253_device::write(offs_t offset, uint8_t data)
m_counter[offset]->count_w(data);
}
-void pit_counter_device::gate_w(int state)
+void pit_counter_device::gate_w_deferred(int state)
{
LOG2("gate_w(): state=%d\n", state);
@@ -1070,6 +1093,7 @@ void pit_counter_device::set_clockin(double new_clockin)
if (started())
update();
m_clockin = new_clockin;
+ m_clock_period = (new_clockin != 0) ? attotime::from_hz(new_clockin) : attotime::never;
if (started())
update();
}
diff --git a/src/devices/machine/pit8253.h b/src/devices/machine/pit8253.h
index 13b222478f5..a862dee8aad 100644
--- a/src/devices/machine/pit8253.h
+++ b/src/devices/machine/pit8253.h
@@ -42,6 +42,14 @@ class pit_counter_device : public device_t
friend class pit8253_device;
friend class pit8254_device;
+ enum
+ {
+ TID_UPDATE = 1,
+ TID_CONTROL,
+ TID_COUNT,
+ TID_GATE
+ };
+
public:
// construction/destruction
pit_counter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -54,6 +62,7 @@ protected:
private:
inline uint32_t adjusted_count() const;
+ inline void adjust_timer(attotime target);
void decrease_counter_value(int64_t cycles);
void load_counter_value();
void set_output(int output);
@@ -63,18 +72,23 @@ private:
uint8_t read();
void load_count(uint16_t newcount);
void readback(int command);
- void control_w(uint8_t data);
- void count_w(uint8_t data);
- void gate_w(int state);
+ void control_w(uint8_t data) { synchronize(TID_CONTROL, data); }
+ void control_w_deferred(uint8_t data);
+ void count_w(uint8_t data) { synchronize(TID_COUNT, data); }
+ void count_w_deferred(uint8_t data);
+ void gate_w(int state) { synchronize(TID_GATE, state); }
+ void gate_w_deferred(int state);
void set_clock_signal(int state);
void set_clockin(double new_clockin);
// internal state
int m_index; // index number of the timer
double m_clockin; // input clock frequency in Hz
+ attotime m_clock_period; // precomputed input clock period
int m_clock_signal; // clock signal when clockin is 0
attotime m_last_updated; // time when last updated
+ attotime m_next_update; // time of next update
emu_timer *m_updatetimer; // MAME timer to process updates
diff --git a/src/devices/sound/sp0250.cpp b/src/devices/sound/sp0250.cpp
index 898bd778dad..03d5004f695 100644
--- a/src/devices/sound/sp0250.cpp
+++ b/src/devices/sound/sp0250.cpp
@@ -21,34 +21,32 @@
#include "emu.h"
#include "sp0250.h"
-/*
-standard external clock is 3.12MHz
-the chip provides a 445.7kHz output clock, which is = 3.12MHz / 7
-therefore I expect the clock divider to be a multiple of 7
-Also there are 6 cascading filter stages so I expect the divider to be a multiple of 6.
-
-The SP0250 manual states that the original speech is sampled at 10kHz, so the divider
-should be 312, but 312 = 39*8 so it doesn't look right because a divider by 39 is unlikely.
+//
+// Input clock is divided by 2 to make ROMCLOCK.
+// Output is via pulse-width modulation (PWM) over the course of 39 ROMCLOCKs.
+// 4 PWM periods per frame.
+//
+static constexpr int PWM_CLOCKS = 39;
-7*6*8 = 336 gives a 9.286kHz sample rate and matches the samples from the Sega boards.
-*/
-#define CLOCK_DIVIDER (7*6*8)
DEFINE_DEVICE_TYPE(SP0250, sp0250_device, "sp0250", "GI SP0250 LPC")
sp0250_device::sp0250_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, SP0250, tag, owner, clock),
device_sound_interface(mconfig, *this),
+ m_pwm_mode(false),
+ m_pwm_index(PWM_CLOCKS),
+ m_pwm_count(0),
+ m_pwm_counts(0),
+ m_voiced(0),
m_amp(0),
+ m_lfsr(0x7fff),
m_pitch(0),
- m_repeat(0),
m_pcount(0),
+ m_repeat(0),
m_rcount(0),
- m_playing(0),
- m_RNG(0),
- m_stream(nullptr),
- m_voiced(0),
m_fifo_pos(0),
+ m_stream(nullptr),
m_drq(*this)
{
for (auto & elem : m_fifo)
@@ -71,29 +69,55 @@ sp0250_device::sp0250_device(const machine_config &mconfig, const char *tag, dev
void sp0250_device::device_start()
{
- m_RNG = 1;
+ // output PWM data at the ROMCLOCK frequency
+ int sample_rate = clock() / 2;
+ int frame_rate = sample_rate / (4 * PWM_CLOCKS);
+ if (!m_pwm_mode)
+ m_stream = machine().sound().stream_alloc(*this, 0, 1, frame_rate);
+ else
+ m_stream = machine().sound().stream_alloc(*this, 0, 1, sample_rate);
+
+ // if a DRQ callback is offered, run a timer at the frame rate
+ // to ensure the DRQ gets picked up in a timely manner
m_drq.resolve_safe();
if (!m_drq.isnull())
{
m_drq(ASSERT_LINE);
- m_tick_timer= machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sp0250_device::timer_tick), this));
- m_tick_timer->adjust(attotime::from_hz(clock()) * CLOCK_DIVIDER, 0, attotime::from_hz(clock()) * CLOCK_DIVIDER);
+ attotime period = attotime::from_hz(frame_rate);
+ timer_alloc()->adjust(period, 0, period);
}
- m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / CLOCK_DIVIDER);
+ // PWM state
+ save_item(NAME(m_pwm_index));
+ save_item(NAME(m_pwm_count));
+ save_item(NAME(m_pwm_counts));
+ // LPC state
+ save_item(NAME(m_voiced));
save_item(NAME(m_amp));
+ save_item(NAME(m_lfsr));
save_item(NAME(m_pitch));
- save_item(NAME(m_repeat));
save_item(NAME(m_pcount));
+ save_item(NAME(m_repeat));
save_item(NAME(m_rcount));
- save_item(NAME(m_playing));
- save_item(NAME(m_RNG));
- save_item(NAME(m_voiced));
+ for (int index = 0; index < 6; index++)
+ {
+ save_item(NAME(m_filter[index].F), index);
+ save_item(NAME(m_filter[index].B), index);
+ save_item(NAME(m_filter[index].z1), index);
+ save_item(NAME(m_filter[index].z2), index);
+ }
+
+ // FIFO state
save_item(NAME(m_fifo));
save_item(NAME(m_fifo_pos));
}
+void sp0250_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ m_stream->update();
+}
+
static uint16_t sp0250_ga(uint8_t v)
{
return (v & 0x1f) << (v>>5);
@@ -140,19 +164,11 @@ void sp0250_device::load_values()
m_filter[5].F = sp0250_gc(m_fifo[14]);
m_fifo_pos = 0;
m_drq(ASSERT_LINE);
-
m_pcount = 0;
m_rcount = 0;
for (int f = 0; f < 6; f++)
- m_filter[f].z1 = m_filter[f].z2 = 0;
-
- m_playing = 1;
-}
-
-TIMER_CALLBACK_MEMBER( sp0250_device::timer_tick )
-{
- m_stream->update();
+ m_filter[f].reset();
}
void sp0250_device::write(uint8_t data)
@@ -175,6 +191,79 @@ uint8_t sp0250_device::drq_r()
return (m_fifo_pos == 15) ? CLEAR_LINE : ASSERT_LINE;
}
+int8_t sp0250_device::next()
+{
+ if (m_rcount >= m_repeat)
+ {
+ if (m_fifo_pos == 15)
+ load_values();
+ else
+ {
+ // According to http://www.cpcwiki.eu/index.php/SP0256_Measured_Timings
+ // the SP0250 executes "NOPs" with a repeat count of 1 and unchanged
+ // pitch while waiting for input
+ m_repeat = 1;
+ m_pcount = 0;
+ m_rcount = 0;
+ }
+ }
+
+ int16_t z0;
+ if (m_voiced)
+ z0 = (m_pcount == 0) ? m_amp : 0;
+ else
+ {
+ z0 = (m_lfsr & 1) ? m_amp : -m_amp;
+
+ // 15-bit LFSR algorithm verified by dump from actual hardware
+ m_lfsr ^= (m_lfsr ^ (m_lfsr >> 1)) << 15;
+ m_lfsr >>= 1;
+ }
+
+ for (int f = 0; f < 6; f++)
+ z0 = m_filter[f].apply(z0);
+
+ // maximum amp value is effectively 13 bits
+ // reduce to 7 bits; due to filter effects it
+ // may occasionally clip
+ int dac = z0 >> 6;
+ if (dac < -64)
+ dac = -64;
+ if (dac > 63)
+ dac = 63;
+
+ // PWM is divided into 4x 5-bit sections; the lower
+ // bits of the original 7-bit value are added to only
+ // some of the pulses in the following pattern:
+ //
+ // DAC -64 -> 1,1,1,1
+ // DAC -63 -> 2,1,1,1
+ // DAC -62 -> 2,1,2,1
+ // DAC -61 -> 2,2,2,1
+ // DAC -60 -> 2,2,2,2
+ // ...
+ // DAC -1 -> 17,17,17,16
+ // DAC 0 -> 17,17,17,17
+ // DAC 1 -> 18,17,17,17
+ // ...
+ // DAC 60 -> 32,32,32,32
+ // DAC 61 -> 33,32,32,32
+ // DAC 62 -> 33,32,33,32
+ // DAC 63 -> 33,33,33,32
+ m_pwm_counts = (((dac + 68 + 3) >> 2) << 0) +
+ (((dac + 68 + 1) >> 2) << 8) +
+ (((dac + 68 + 2) >> 2) << 16) +
+ (((dac + 68 + 0) >> 2) << 24);
+
+ m_pcount++;
+ if (m_pcount >= m_pitch)
+ {
+ m_pcount = 0;
+ m_rcount++;
+ }
+ return dac;
+}
+
//-------------------------------------------------
// sound_stream_update - handle a stream update
//-------------------------------------------------
@@ -182,62 +271,49 @@ uint8_t sp0250_device::drq_r()
void sp0250_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
stream_sample_t *output = outputs[0];
- for (int i = 0; i < samples; i++)
+ if (!m_pwm_mode)
{
- if (m_playing)
+ while (samples-- != 0)
+ *output++ = next() << 8;
+ }
+ else
+ {
+ while (samples != 0)
{
- int16_t z0;
-
- if (m_voiced)
+ // see where we're at in the current PWM cycle
+ if (m_pwm_index >= PWM_CLOCKS)
{
- if(!m_pcount)
- z0 = m_amp;
- else
- z0 = 0;
- }
- else
- {
- // Borrowing the ay noise generation LFSR
- if(m_RNG & 1)
- {
- z0 = m_amp;
- m_RNG ^= 0x24000;
- }
- else
- z0 = -m_amp;
-
- m_RNG >>= 1;
+ m_pwm_index = 0;
+ if (m_pwm_counts == 0)
+ next();
+ m_pwm_count = m_pwm_counts & 0xff;
+ m_pwm_counts >>= 8;
}
- for (int f = 0; f < 6; f++)
+ // determine the value to fill and the number of samples remaining
+ // until it changes
+ stream_sample_t value;
+ int remaining;
+ if (m_pwm_index < m_pwm_count)
{
- z0 += ((m_filter[f].z1 * m_filter[f].F) >> 8)
- + ((m_filter[f].z2 * m_filter[f].B) >> 9);
- m_filter[f].z2 = m_filter[f].z1;
- m_filter[f].z1 = z0;
+ value = 32767;
+ remaining = m_pwm_count - m_pwm_index;
}
-
- // Physical resolution is only 7 bits, but heh
-
- // max amplitude is 0x0f80 so we have margin to push up the output
- output[i] = z0 << 3;
-
- m_pcount++;
- if (m_pcount >= m_pitch)
+ else
{
- m_pcount = 0;
- m_rcount++;
- if (m_rcount >= m_repeat)
- m_playing = 0;
+ value = 0;
+ remaining = PWM_CLOCKS - m_pwm_index;
}
- }
- else
- output[i] = 0;
- if (!m_playing)
- {
- if(m_fifo_pos == 15)
- load_values();
+ // clamp to the number of samples requested and advance the counters
+ if (remaining > samples)
+ remaining = samples;
+ m_pwm_index += remaining;
+ samples -= remaining;
+
+ // fill the output
+ while (remaining-- != 0)
+ *output++ = value;
}
}
}
diff --git a/src/devices/sound/sp0250.h b/src/devices/sound/sp0250.h
index 9685fa4fea2..48f77a69d01 100644
--- a/src/devices/sound/sp0250.h
+++ b/src/devices/sound/sp0250.h
@@ -11,6 +11,7 @@ public:
sp0250_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto drq() { return m_drq.bind(); }
+ void set_pwm_mode() { m_pwm_mode = true; }
void write(uint8_t data);
uint8_t drq_r();
@@ -18,33 +19,56 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// sound stream update overrides
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
private:
- // internal state
- int16_t m_amp;
- uint8_t m_pitch;
- uint8_t m_repeat;
- int m_pcount, m_rcount;
- int m_playing;
- uint32_t m_RNG;
- sound_stream * m_stream;
- int m_voiced;
- uint8_t m_fifo[15];
- int m_fifo_pos;
- devcb_write_line m_drq;
+ // internal helpers
+ int8_t next();
+ void load_values();
- struct
+ // state for each filter
+ class filter
{
+ public:
+ filter() : z1(0), z2(0) { }
+ void reset() { z1 = z2 = 0; }
+ int16_t apply(int16_t in)
+ {
+ int16_t z0 = in + ((z1 * F) >> 8) + ((z2 * B) >> 9);
+ z2 = z1;
+ z1 = z0;
+ return z0;
+ }
int16_t F, B;
int16_t z1, z2;
- } m_filter[6];
+ };
- void load_values();
- TIMER_CALLBACK_MEMBER( timer_tick );
- emu_timer * m_tick_timer;
+ // PWM state
+ bool m_pwm_mode;
+ uint8_t m_pwm_index;
+ uint8_t m_pwm_count;
+ uint32_t m_pwm_counts;
+
+ // LPC state
+ bool m_voiced;
+ int16_t m_amp;
+ uint16_t m_lfsr;
+ uint8_t m_pitch;
+ uint8_t m_pcount;
+ uint8_t m_repeat;
+ uint8_t m_rcount;
+ filter m_filter[6];
+
+ // FIFO state
+ uint8_t m_fifo[15];
+ uint8_t m_fifo_pos;
+
+ // external interfacing
+ sound_stream *m_stream;
+ devcb_write_line m_drq;
};
DECLARE_DEVICE_TYPE(SP0250, sp0250_device)
diff --git a/src/lib/netlist/devices/nld_4020.cpp b/src/lib/netlist/devices/nld_4020.cpp
index 4143f66da8d..9e2dd386654 100644
--- a/src/lib/netlist/devices/nld_4020.cpp
+++ b/src/lib/netlist/devices/nld_4020.cpp
@@ -46,17 +46,15 @@ namespace netlist
namespace devices
{
- template <unsigned _LiveBitmask>
+ template <unsigned _TotalBits, unsigned _LiveBitmask>
NETLIB_OBJECT(CD4020_sub)
{
- static constexpr unsigned MAX_BITS = 14;
- static constexpr unsigned MAX_BITMASK = (1 << MAX_BITS) - 1;
+ static_assert((_LiveBitmask >> _TotalBits) == 0, "Live bitmask too large");
NETLIB_CONSTRUCTOR_MODEL(CD4020_sub, "CD4XXX")
, m_IP(*this, "IP", NETLIB_DELEGATE(ip))
, m_RESET(*this, "RESET", NETLIB_DELEGATE(reseti))
- , m_Q(*this, {"Q1", "_Q2", "_Q3", "Q4", "Q5", "Q6", "Q7", "Q8", "Q9",
- "Q10", "Q11", "Q12", "Q13", "Q14"})
+ , m_Q(*this, 1, "Q{}")
, m_cnt(*this, "m_cnt", 0)
, m_supply(*this)
{
@@ -81,7 +79,7 @@ namespace netlist
m_cnt = 0;
m_IP.inactivate();
/* static */ const netlist_time reset_time = netlist_time::from_nsec(140);
- for (unsigned i = 0; i < MAX_BITS; i++)
+ for (int i = 0; i < _TotalBits; i++)
if (((_LiveBitmask >> i) & 1) != 0)
m_Q[i].push(0, reset_time);
}
@@ -102,13 +100,13 @@ namespace netlist
NLTIME_FROM_NS(1380), NLTIME_FROM_NS(1480),
};
- for (unsigned i = 0; i < MAX_BITS; i++)
+ for (int i = 0; i < _TotalBits; i++)
if (((_LiveBitmask >> i) & 1) != 0)
- m_Q[i].push(cnt & 1, out_delayQn[i]);
+ m_Q[i].push((cnt >> i) & 1, out_delayQn[i]);
}
logic_input_t m_IP;
logic_input_t m_RESET;
- object_array_t<logic_output_t, MAX_BITS> m_Q;
+ object_array_t<logic_output_t, _TotalBits> m_Q;
state_var<unsigned> m_cnt;
nld_power_pins m_supply;
@@ -140,7 +138,7 @@ namespace netlist
//NETLIB_RESETI() {}
private:
- NETLIB_SUB(CD4020_sub)<0x3ff9> m_sub;
+ NETLIB_SUB(CD4020_sub)<14, 0x3ff9> m_sub;
};
NETLIB_OBJECT(CD4024)
@@ -164,7 +162,7 @@ namespace netlist
//NETLIB_RESETI() {}
private:
- NETLIB_SUB(CD4020_sub)<0x7f> m_sub;
+ NETLIB_SUB(CD4020_sub)<7, 0x7f> m_sub;
};
diff --git a/src/lib/netlist/devices/nld_4053.cpp b/src/lib/netlist/devices/nld_4053.cpp
index 62db781fbfa..5056b453622 100644
--- a/src/lib/netlist/devices/nld_4053.cpp
+++ b/src/lib/netlist/devices/nld_4053.cpp
@@ -48,19 +48,14 @@ namespace netlist
, m_supply(*this)
{
connect(m_RX.N(), m_RY.N());
-
register_subalias("X", m_RX.P());
register_subalias("Y", m_RY.P());
-
register_subalias("XY", m_RX.N());
}
NETLIB_RESETI()
{
- // Start in off condition
- // FIXME: is ROFF correct?
- m_RX.set_R(plib::reciprocal(exec().gmin()));
- m_RY.set_R(plib::reciprocal(exec().gmin()));
+ update_state(true, false);
}
private:
@@ -80,40 +75,16 @@ namespace netlist
}
if (newx != m_lastx || newy != m_lasty)
- {
- const nl_fptype sup = (m_supply.VCC().Q_Analog() - m_supply.GND().Q_Analog());
- const nl_fptype Ron = m_base_r() * nlconst::magic(5.0) / sup;
- const nl_fptype Roff = plib::reciprocal(exec().gmin());
- const nl_fptype RX = (newx != 0) ? Ron : Roff;
- const nl_fptype RY = (newy != 0) ? Ron : Roff;
- if (m_RX.solver() == m_RY.solver())
- {
- m_RX.change_state([this, &RX, &RY]()
- {
- m_RX.set_R(RX);
- m_RY.set_R(RY);
- });
- }
- else
- {
- m_RX.change_state([this, &RX]()
- {
- m_RX.set_R(RX);
- });
- m_RY.change_state([this, &RY]()
- {
- m_RY.set_R(RY);
- });
- }
- }
+ update_state(newx, newy);
}
bool on(analog_input_t &input, bool &state)
{
+ // digital inputs are based on VDD
nl_fptype sup = (m_supply.VCC().Q_Analog() - m_supply.GND().Q_Analog());
nl_fptype in = input() - m_supply.GND().Q_Analog();
- nl_fptype low = nlconst::magic(0.45) * sup;
- nl_fptype high = nlconst::magic(0.55) * sup;
+ nl_fptype low = nlconst::magic(0.3) * sup;
+ nl_fptype high = nlconst::magic(0.7) * sup;
if (in < low)
{
state = false;
@@ -125,6 +96,37 @@ namespace netlist
return state;
}
+ void update_state(bool newx, bool newy)
+ {
+ // analog output is based on VEE
+ const nl_fptype sup = (m_VEE() - m_supply.GND().Q_Analog());
+ const nl_fptype Ron = m_base_r() * nlconst::magic(5.0) / sup;
+ const nl_fptype Roff = plib::reciprocal(exec().gmin());
+ const nl_fptype RX = newx ? Ron : Roff;
+ const nl_fptype RY = newy ? Ron : Roff;
+ if (m_RX.solver() == m_RY.solver())
+ {
+ m_RX.change_state([this, &RX, &RY]()
+ {
+ m_RX.set_R(RX);
+ m_RY.set_R(RY);
+ });
+ }
+ else
+ {
+ m_RX.change_state([this, &RX]()
+ {
+ m_RX.set_R(RX);
+ });
+ m_RY.change_state([this, &RY]()
+ {
+ m_RY.set_R(RY);
+ });
+ }
+ m_lastx = newx;
+ m_lasty = newy;
+ }
+
analog::NETLIB_SUB(R_base) m_RX;
analog::NETLIB_SUB(R_base) m_RY;
analog_input_t m_select;
diff --git a/src/lib/netlist/devices/nld_devinc.h b/src/lib/netlist/devices/nld_devinc.h
index 1a1e7d2865f..5780106c96b 100644
--- a/src/lib/netlist/devices/nld_devinc.h
+++ b/src/lib/netlist/devices/nld_devinc.h
@@ -1021,6 +1021,10 @@
#define TTL_74113A_DIP(...) \
NET_REGISTER_DEVEXT(TTL_74113A_DIP, __VA_ARGS__)
+// usage : TTL_74139_GATE(name)
+#define TTL_74139_GATE(...) \
+ NET_REGISTER_DEVEXT(TTL_74139_GATE, __VA_ARGS__)
+
// usage : TTL_74155A_GATE(name)
#define TTL_74155A_GATE(...) \
NET_REGISTER_DEVEXT(TTL_74155A_GATE, __VA_ARGS__)
@@ -1202,6 +1206,10 @@
#define TTL_74126_DIP(...) \
NET_REGISTER_DEVEXT(TTL_74126_DIP, __VA_ARGS__)
+// usage : TTL_74139_DIP(name)
+#define TTL_74139_DIP(...) \
+ NET_REGISTER_DEVEXT(TTL_74139_DIP, __VA_ARGS__)
+
// usage : TTL_74153_DIP(name)
#define TTL_74153_DIP(...) \
NET_REGISTER_DEVEXT(TTL_74153_DIP, __VA_ARGS__)
@@ -1387,6 +1395,10 @@
#define TL081_DIP(...) \
NET_REGISTER_DEVEXT(TL081_DIP, __VA_ARGS__)
+// usage : TL082_DIP(name)
+#define TL082_DIP(...) \
+ NET_REGISTER_DEVEXT(TL082_DIP, __VA_ARGS__)
+
// usage : TL084_DIP(name)
#define TL084_DIP(...) \
NET_REGISTER_DEVEXT(TL084_DIP, __VA_ARGS__)
diff --git a/src/lib/netlist/macro/nlm_opamp_lib.cpp b/src/lib/netlist/macro/nlm_opamp_lib.cpp
index a8fae82e8c8..94c5da23686 100644
--- a/src/lib/netlist/macro/nlm_opamp_lib.cpp
+++ b/src/lib/netlist/macro/nlm_opamp_lib.cpp
@@ -314,6 +314,14 @@ static NETLIST_START(TL081_DIP)
NETLIST_END()
+static NETLIST_START(TL082_DIP)
+ OPAMP(A, "TL084")
+ OPAMP(B, "TL084")
+
+ INCLUDE(opamp_layout_2_8_4)
+
+NETLIST_END()
+
static NETLIST_START(TL084_DIP)
OPAMP(A, "TL084")
OPAMP(B, "TL084")
@@ -594,6 +602,7 @@ NETLIST_START(opamp_lib)
LOCAL_LIB_ENTRY(MB3614_DIP)
LOCAL_LIB_ENTRY(MC3340_DIP)
LOCAL_LIB_ENTRY(TL081_DIP)
+ LOCAL_LIB_ENTRY(TL082_DIP)
LOCAL_LIB_ENTRY(TL084_DIP)
LOCAL_LIB_ENTRY(LM324_DIP)
LOCAL_LIB_ENTRY(LM358_DIP)
diff --git a/src/lib/netlist/macro/nlm_opamp_lib.h b/src/lib/netlist/macro/nlm_opamp_lib.h
index 7c9b31a29bd..362e5c7baa1 100644
--- a/src/lib/netlist/macro/nlm_opamp_lib.h
+++ b/src/lib/netlist/macro/nlm_opamp_lib.h
@@ -27,6 +27,9 @@
#define TL081_DIP(name) \
NET_REGISTER_DEV(TL081_DIP, name)
+#define TL082_DIP(name) \
+ NET_REGISTER_DEV(TL082_DIP, name)
+
#define TL084_DIP(name) \
NET_REGISTER_DEV(TL084_DIP, name)
diff --git a/src/lib/netlist/macro/nlm_ttl74xx_lib.cpp b/src/lib/netlist/macro/nlm_ttl74xx_lib.cpp
index 92f486aac5a..0d3754e94d7 100644
--- a/src/lib/netlist/macro/nlm_ttl74xx_lib.cpp
+++ b/src/lib/netlist/macro/nlm_ttl74xx_lib.cpp
@@ -1822,6 +1822,52 @@ static NETLIST_START(TTL_74126_DIP)
)
NETLIST_END()
+//- Identifier: TTL_74139_DIP
+//- Title: 54LS139/DM54LS139/DM74LS139 Decoders/Demultiplexers
+//- Description: These Schottky-clamped circuits are designed to be used in high-performance memory-decoding or data-routing applications, requiring very short propagation delay times.
+//- In high-performance memory systems these decoders can be used to minimize the effects of system decoding.
+//- When used with high-speed memories, the delay times of these decoders are usually less than the typical access time of the memory.
+//- This means that the effective system delay introduced by the decoder is negligible.
+//- The LS139 comprises two separate two-line-to-four-line decoders in a single package.
+//- The active-low enable input can be used as a data line in demultiplexing applications.
+//- All of these decoders/demultiplexers feature fully buffered inputs, presenting only one normalized load to its driving circuit.
+// All inputs are clamped with high-performance Schottky diodes to suppress line-ringing and simplify system design.
+//- Pinalias: G1,A1,B1,1Y0,1Y1,1Y2,1Y3,GND,2Y3,2Y2,2Y1,2Y0,B2,A2,G2,VCC
+//- Package: DIP
+//- NamingConvention: Naming conventions follow National Semiconductor datasheet
+//- FunctionTable:
+//- pdf.datasheetcatalog.com/datasheets/166/375388_DS.pdf
+//-
+//- +---+-------+-------------+
+//- | E | A0 A1 | O0 O1 O2 O3 |
+//- +===+=======+=============+
+//- | 1 | X X | 1 1 1 1 |
+//- | 0 | 0 0 | 0 1 1 1 |
+//- | 0 | 1 0 | 1 0 1 1 |
+//- | 0 | 0 1 | 1 1 0 1 |
+//- | 0 | 1 1 | 1 1 1 0 |
+//- +---+-------+-------------+
+//-
+static NETLIST_START(TTL_74139_DIP)
+ NET_REGISTER_DEV(TTL_74139_GATE, A)
+ NET_REGISTER_DEV(TTL_74139_GATE, B)
+
+ NET_C(A.VCC, B.VCC)
+ NET_C(A.GND, B.GND)
+
+ DIPPINS( /* +--------------+ */
+ A.E, /* /Ea |1 ++ 16| VCC */ A.VCC,
+ A.A, /* A0a |2 15| /Eb */ B.E,
+ A.B, /* A1a |3 14| A0b */ B.A,
+ A.0, /* /O0a |4 74139 13| A1b */ B.B,
+ A.1, /* /O1a |5 12| /O0b */ B.0,
+ A.2, /* /O2a |6 11| /O1b */ B.1,
+ A.3, /* /O3a |7 10| /O2b */ B.2,
+ A.GND,/* GND |8 9| /O3b */ B.3
+ /* +--------------+ */
+ )
+NETLIST_END()
+
//- Identifier: TTL_74153_DIP
//- Title: 54153/DM54153/DM74153 Dual 4-Line to 1-LineData Selectors/Multiplexers
//- Description: Each of these data selectors/multiplexers contains inverters and drivers to supply fully complementary, on-chip, binary decoding data selection to the AND-OR-invert gates.
@@ -3205,6 +3251,16 @@ NETLIST_START(ttl74xx_lib)
TRUTHTABLE_END()
+ TRUTHTABLE_START(TTL_74139_GATE, 3, 4, "")
+ TT_HEAD("E,A,B|0,1,2,3")
+ TT_LINE("1,X,X|1,1,1,1|14")
+ TT_LINE("0,0,0|0,1,1,1|14")
+ TT_LINE("0,0,1|1,0,1,1|14")
+ TT_LINE("0,1,0|1,1,0,1|14")
+ TT_LINE("0,1,1|1,1,1,0|14")
+ TT_FAMILY("74XX")
+ TRUTHTABLE_END()
+
TRUTHTABLE_START(TTL_74155A_GATE, 4, 4, "")
TT_HEAD("B,A,G,C|0,1,2,3")
TT_LINE("X,X,1,X|1,1,1,1|13,13,13,13")
@@ -3367,6 +3423,7 @@ NETLIST_START(ttl74xx_lib)
LOCAL_LIB_ENTRY(TTL_9602_DIP)
LOCAL_LIB_ENTRY(TTL_74125_DIP)
LOCAL_LIB_ENTRY(TTL_74126_DIP)
+ LOCAL_LIB_ENTRY(TTL_74139_DIP)
LOCAL_LIB_ENTRY(TTL_74153_DIP)
LOCAL_LIB_ENTRY(TTL_74155_DIP)
LOCAL_LIB_ENTRY(TTL_74156_DIP)
diff --git a/src/lib/netlist/macro/nlm_ttl74xx_lib.h b/src/lib/netlist/macro/nlm_ttl74xx_lib.h
index d864f148c7e..ce91782b5e6 100644
--- a/src/lib/netlist/macro/nlm_ttl74xx_lib.h
+++ b/src/lib/netlist/macro/nlm_ttl74xx_lib.h
@@ -324,6 +324,9 @@
#define TTL_74125_DIP(name) \
NET_REGISTER_DEV(TTL_74125_DIP, name)
+#define TTL_74139_DIP(name) \
+ NET_REGISTER_DEV(TTL_74139_DIP, name)
+
#define TTL_74153_DIP(name) \
NET_REGISTER_DEV(TTL_74153_DIP, name)
diff --git a/src/lib/netlist/nl_errstr.h b/src/lib/netlist/nl_errstr.h
index e5844bbb4ab..553387301d9 100644
--- a/src/lib/netlist/nl_errstr.h
+++ b/src/lib/netlist/nl_errstr.h
@@ -55,7 +55,9 @@ namespace netlist
// nl_setup.cpp
PERRMSGV(MF_UNABLE_TO_PARSE_MODEL_1, 1, "Unable to parse model: {1}")
- PERRMSGV(MF_MODEL_ALREADY_EXISTS_1, 1, "Model already exists: {1}")
+ // FIXME: Add an directive MODEL_OVERWRITE to netlist language
+ //PERRMSGV(MF_MODEL_ALREADY_EXISTS_1, 1, "Model already exists: {1}")
+ PERRMSGV(MI_MODEL_OVERWRITE_1, 2, "Model already exists, overwriting {1} with {2}")
PERRMSGV(MF_DEVICE_ALREADY_EXISTS_1, 1, "Device already exists: {1}")
PERRMSGV(MF_UNUSED_HINT_1, 1, "Error hint {1} is not used")
PERRMSGV(MF_ADDING_HINT_1, 1, "Error adding hint {1} to hint list")
diff --git a/src/lib/netlist/nl_setup.cpp b/src/lib/netlist/nl_setup.cpp
index 394d5008f00..70860747f93 100644
--- a/src/lib/netlist/nl_setup.cpp
+++ b/src/lib/netlist/nl_setup.cpp
@@ -448,7 +448,12 @@ namespace netlist
pstring model = plib::ucase(plib::trim(plib::left(model_in, pos)));
pstring def = plib::trim(model_in.substr(pos + 1));
if (!m_abstract.m_models.insert({model, def}).second)
- throw nl_exception(MF_MODEL_ALREADY_EXISTS_1(model_in));
+ {
+ // FIXME: Add an directive MODEL_OVERWRITE to netlist language
+ //throw nl_exception(MF_MODEL_ALREADY_EXISTS_1(model_in));
+ log().info(MI_MODEL_OVERWRITE_1(model, model_in));
+ m_abstract.m_models[model] = def;
+ }
}
@@ -1623,6 +1628,7 @@ void setup_t::prepare_to_run()
// resolve inputs
resolve_inputs();
+#if 0
log().verbose("looking for two terms connected to rail nets ...");
for (auto & t : m_nlstate.get_device_list<analog::NETLIB_NAME(twoterm)>())
{
@@ -1638,6 +1644,7 @@ void setup_t::prepare_to_run()
#endif
}
}
+#endif
log().verbose("looking for unused hints ...");
for (auto &h : m_abstract.m_hints)
diff --git a/src/mame/audio/nl_astrob.cpp b/src/mame/audio/nl_astrob.cpp
new file mode 100644
index 00000000000..90d3d6c98ed
--- /dev/null
+++ b/src/mame/audio/nl_astrob.cpp
@@ -0,0 +1,1161 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+
+//
+// Netlist for Astro Blaster
+//
+// Derived from the schematics in the Astro Blaster manual.
+//
+// Known problems/issues:
+//
+// * All sounds work under the right conditions.
+//
+// * SONAR and BONUS sounds fail to trigger after the first
+// few seconds. For some reason the triggering via CD4011
+// never actually fires the one-shot that controls the
+// duration of the sound.
+//
+// * Performance is poor, primarily due to the SONAR sound
+// and its connection to the mixing net. All attempts at
+// separating the two have ended in failure so far.
+//
+
+#include "netlist/devices/net_lib.h"
+#include "nl_astrob.h"
+
+
+//
+// Optimizations
+//
+
+#define HLE_LASER_1_VCO (1)
+#define HLE_LASER_2_VCO (1)
+#define SIMPLIFY_SONAR (1)
+#define ENABLE_FRONTIERS (1)
+#define UNDERCLOCK_NOISE_GEN (1)
+
+
+
+//
+// Hacks
+//
+
+#define ADD_CLIPPING_DIODES (1)
+
+
+
+// not really found anywhere, just took the 5239 and changed the
+// breakdown voltage to 5.1 according to the datasheet
+#define D_1N5231(name) ZDIODE(name, "D(BV=5.1 IBV=0.020 NBV=1)")
+#define D_1N914(name) DIODE(name, "1N914")
+
+// SPICE model taken from https://www.onsemi.com/support/design-resources/models?rpn=2N4403
+#define Q_2N4403(name) QBJT_EB(name, "PNP(Is=650.6E-18 Xti=3 Eg=1.11 Vaf=115.7 Bf=216.2 Ne=1.829 Ise=58.72f Ikf=1.079 Xtb=1.5 Br=3.578 Nc=2 Isc=0 Ikr=0 Rc=.715 Cjc=14.76p Mjc=.5383 Vjc=.75 Fc=.5 Cje=19.82p Mje=.3357 Vje=.75 Tr=111.6n Tf=603.7p Itf=.65 Vtf=5 Xtf=1.7 Rb=10)")
+
+// JFET transistors not supported, but this should do the trick
+#define Q_2N4093(name) MOSFET(name, "NMOS(VTO=-1 CAPMOD=0)")
+
+#define LM555_DIP NE555_DIP
+#define LM566_DIP NE566_DIP
+
+#define TTL_74LS00_DIP TTL_7400_DIP
+#define TTL_74LS04_DIP TTL_7404_DIP
+
+
+
+//
+// Main netlist
+//
+
+NETLIST_START(astrob)
+
+#if 1
+ SOLVER(Solver, 1000)
+ PARAM(Solver.DYNAMIC_TS, 1)
+ PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 4e-5)
+#if (SIMPLIFY_SONAR)
+ PARAM(Solver.Solver_54.DYNAMIC_MIN_TIMESTEP, 7e-6) // gets rid of NR loops failure
+#else
+ PARAM(Solver.Solver_40.DYNAMIC_MIN_TIMESTEP, 7e-6) // gets rid of NR loops failure
+#endif
+#else
+ SOLVER(Solver, 48000)
+#endif
+
+ // Overwrite model - the default model uses minimum datasheet
+ // specifications for 5V. These are for 10V and thus closer to the
+ // 12V used in this circuit.
+ NET_MODEL("CD4XXX FAMILY(TYPE=CMOS IVL=0.3 IVH=0.7 OVL=0.05 OVH=0.05 ORL=384 ORH=384)")
+
+ TTL_INPUT(I_LO_D0, 0)
+ NET_C(I_LO_D0, U31.1)
+ ALIAS(I_INVADER_1, U31.2)
+ TTL_INPUT(I_LO_D1, 0)
+ NET_C(I_LO_D1, U31.3)
+ ALIAS(I_INVADER_2, U31.4)
+ TTL_INPUT(I_LO_D2, 0)
+ NET_C(I_LO_D2, U31.11)
+ ALIAS(I_INVADER_3, U31.10)
+ TTL_INPUT(I_LO_D3, 0)
+ NET_C(I_LO_D3, U31.9)
+ ALIAS(I_INVADER_4, U31.8)
+ TTL_INPUT(I_LO_D4, 0)
+ NET_C(I_LO_D4, U30.13)
+ ALIAS(I_ASTROIDS, U30.12)
+ TTL_INPUT(I_LO_D5, 0)
+ ALIAS(I_MUTE, I_LO_D5)
+ TTL_INPUT(I_LO_D6, 0)
+ NET_C(I_LO_D6, U30.3, U29.11)
+ ALIAS(I_REFILL, U29.10)
+ ALIAS(I_REFILL_Q, U30.4)
+ TTL_INPUT(I_LO_D7, 0)
+ ALIAS(W, I_LO_D7)
+ NET_C(I_LO_D7, U31.5)
+ ALIAS(I_WARP, U31.6)
+
+ NET_C(GND, I_LO_D0.GND, I_LO_D1.GND, I_LO_D2.GND, I_LO_D3.GND, I_LO_D4.GND, I_LO_D5.GND, I_LO_D6.GND, I_LO_D7.GND)
+ NET_C(I_V5, I_LO_D0.VCC, I_LO_D1.VCC, I_LO_D2.VCC, I_LO_D3.VCC, I_LO_D4.VCC, I_LO_D5.VCC, I_LO_D6.VCC, I_LO_D7.VCC)
+
+ TTL_INPUT(I_HI_D0, 0)
+ NET_C(I_HI_D0, U26.5)
+ ALIAS(I_LASER_1, U26.6)
+ TTL_INPUT(I_HI_D1, 0)
+ NET_C(I_HI_D1, U26.3)
+ ALIAS(I_LASER_2, U26.4)
+ TTL_INPUT(I_HI_D2, 0)
+ NET_C(I_HI_D2, U26.11)
+ ALIAS(I_SHORT_EXPL, U26.10)
+ TTL_INPUT(I_HI_D3, 0)
+ NET_C(I_HI_D3, U26.9)
+ ALIAS(I_LONG_EXPL, U26.8)
+ TTL_INPUT(I_HI_D4, 0)
+ NET_C(I_HI_D4, U26.1)
+ ALIAS(I_ATTACK_RATE, U26.2)
+ TTL_INPUT(I_HI_D5, 0)
+ NET_C(I_HI_D5, U31.13)
+ ALIAS(I_RATE_RESET, U31.12)
+ TTL_INPUT(I_HI_D6, 0)
+ NET_C(I_HI_D6, U29.9)
+ ALIAS(I_BONUS, U29.8)
+ TTL_INPUT(I_HI_D7, 0)
+ NET_C(I_HI_D7, U29.5)
+ ALIAS(I_SONAR, U29.6)
+
+ NET_C(GND, I_HI_D0.GND, I_HI_D1.GND, I_HI_D2.GND, I_HI_D3.GND, I_HI_D4.GND, I_HI_D5.GND, I_HI_D6.GND, I_HI_D7.GND)
+ NET_C(I_V5, I_HI_D0.VCC, I_HI_D1.VCC, I_HI_D2.VCC, I_HI_D3.VCC, I_HI_D4.VCC, I_HI_D5.VCC, I_HI_D6.VCC, I_HI_D7.VCC)
+
+ ANALOG_INPUT(I_V5, 5)
+ ANALOG_INPUT(I_V12, 12)
+ ANALOG_INPUT(I_VM12, -12)
+
+ RES(R1, RES_K(100))
+ RES(R2, RES_K(1.5))
+ RES(R3, RES_K(330))
+ RES(R4, RES_K(10))
+#if (SIMPLIFY_SONAR)
+ // use less resistance to account for only emulating 1/4 identical circuits
+ RES(R5, RES_K(17))
+#else
+ RES(R5, RES_K(68))
+#endif
+ RES(R6, RES_K(68))
+ RES(R7, RES_K(22))
+ RES(R8, RES_K(18))
+ RES(R9, RES_K(33))
+ RES(R10, RES_K(100))
+ RES(R11, RES_K(150))
+ RES(R12, RES_K(39))
+ RES(R13, RES_K(330))
+ RES(R14, RES_K(47))
+ RES(R15, RES_K(220))
+ RES(R16, RES_K(10))
+ RES(R17, RES_K(10))
+ RES(R18, RES_M(2.7))
+// RES(R19, RES_K(1))
+ RES(R20, RES_M(1))
+ RES(R21, RES_K(100))
+ RES(R22, RES_K(470))
+ RES(R23, RES_K(100))
+ RES(R24, RES_M(2.2))
+ RES(R25, RES_K(10))
+ RES(R26, RES_K(820))
+ RES(R27, RES_K(47))
+ RES(R28, RES_K(22))
+ RES(R29, RES_K(10))
+ RES(R30, RES_K(82))
+ RES(R31, RES_K(10))
+ RES(R32, RES_K(22))
+ RES(R33, RES_K(39))
+ RES(R34, RES_K(4.7))
+ RES(R35, RES_K(4.7))
+ RES(R36, RES_K(100.1)) // part of SONAR circuit that relies on subtle part differences
+ RES(R37, RES_K(1.51)) // part of SONAR circuit that relies on subtle part differences
+ RES(R38, RES_K(330.1)) // part of SONAR circuit that relies on subtle part differences
+ RES(R39, RES_K(10.1)) // part of SONAR circuit that relies on subtle part differences
+ RES(R40, RES_K(68.1)) // part of SONAR circuit that relies on subtle part differences
+ RES(R41, RES_K(10))
+ RES(R42, RES_K(100))
+ RES(R43, RES_K(470))
+ RES(R44, RES_M(1))
+ RES(R45, RES_K(100))
+ RES(R46, RES_K(470))
+ RES(R47, RES_K(10))
+ RES(R48, RES_K(82))
+ RES(R49, RES_K(39))
+ RES(R50, RES_K(22))
+ RES(R51, RES_K(10))
+ RES(R52, RES_K(68))
+ RES(R53, RES_K(10))
+ RES(R54, RES_K(22))
+ RES(R55, RES_M(2.2))
+ RES(R56, RES_K(33))
+ RES(R57, RES_K(33))
+ RES(R58, RES_K(820))
+ RES(R59, RES_K(100))
+ RES(R60, RES_K(10))
+ RES(R61, RES_K(100))
+ RES(R62, RES_K(99.9)) // part of SONAR circuit that relies on subtle part differences
+ RES(R63, RES_K(1.49)) // part of SONAR circuit that relies on subtle part differences
+ RES(R64, RES_K(329.9)) // part of SONAR circuit that relies on subtle part differences
+ RES(R65, RES_K(9.9)) // part of SONAR circuit that relies on subtle part differences
+ RES(R66, RES_K(67.9)) // part of SONAR circuit that relies on subtle part differences
+ RES(R67, RES_K(10))
+ RES(R68, RES_K(82))
+ RES(R69, RES_K(470))
+ RES(R70, RES_K(100))
+ RES(R71, RES_K(10))
+ RES(R72, RES_K(10))
+ RES(R73, RES_K(100))
+ RES(R74, RES_K(4.7))
+ RES(R75, RES_K(100))
+ RES(R76, RES_K(22))
+ RES(R77, RES_K(330))
+ RES(R78, RES_K(1))
+ RES(R79, RES_K(150))
+ RES(R80, RES_M(1))
+ RES(R81, RES_K(10))
+ RES(R82, RES_K(100))
+ RES(R83, RES_K(1))
+ RES(R84, RES_K(5.6))
+ RES(R85, RES_K(150))
+ RES(R86, RES_K(10))
+ RES(R87, RES_K(10))
+ RES(R88, RES_K(100))
+ RES(R89, RES_K(10))
+ RES(R90, RES_K(100))
+ RES(R91, RES_K(100.2)) // part of SONAR circuit that relies on subtle part differences
+ RES(R92, RES_K(1.52)) // part of SONAR circuit that relies on subtle part differences
+ RES(R93, RES_K(330.2)) // part of SONAR circuit that relies on subtle part differences
+ RES(R94, RES_K(10.2)) // part of SONAR circuit that relies on subtle part differences
+ RES(R95, RES_K(68.2)) // part of SONAR circuit that relies on subtle part differences
+ RES(R96, RES_K(10))
+ RES(R97, RES_K(4.7))
+ RES(R98, RES_M(1))
+ RES(R99, RES_M(1))
+ RES(R100, RES_M(1))
+ RES(R101, RES_M(1))
+ RES(R102, RES_K(470))
+ RES(R103, RES_M(1))
+ RES(R104, RES_K(10))
+ RES(R105, RES_K(10))
+ RES(R106, RES_M(2.7))
+ RES(R107, RES_K(100))
+ RES(R108, RES_K(100))
+ RES(R109, RES_K(10))
+ RES(R110, RES_K(10))
+ RES(R111, RES_K(10))
+ RES(R112, RES_K(10))
+ RES(R113, RES_K(10))
+ RES(R114, 100)
+// RES(R115, RES_K(100)) -- part of final amp (not emulated)
+// RES(R116, RES_K(470)) -- part of final amp (not emulated)
+ RES(R117, RES_K(1))
+ RES(R118, RES_K(470))
+ RES(R119, RES_K(470))
+ RES(R120, RES_K(220))
+ RES(R121, RES_K(10))
+ RES(R122, RES_K(4.7))
+// RES(R123, RES_K(1)) -- part of final amp (not emulated)
+// RES(R124, RES_K(100)) -- part of final amp (not emulated)
+ RES(R125, RES_K(82))
+ RES(R126, RES_K(39))
+ RES(R127, RES_K(10))
+ RES(R128, RES_K(22))
+ RES(R129, RES_K(10))
+ RES(R130, RES_K(22))
+ RES(R131, RES_K(39))
+ RES(R132, RES_K(82))
+ RES(R133, RES_K(100))
+ RES(R134, RES_M(2.7))
+// RES(R135, RES_K(22)) -- part of final amp (not emulated)
+ RES(R136, RES_K(1))
+ RES(R137, RES_K(4.7))
+ RES(R138, RES_M(2.2))
+ RES(R139, RES_K(4.7))
+ RES(R140, RES_K(4.7))
+// RES(R141, RES_K(22))
+// RES(R142, RES_M(1)) -- part of final amp (not emulated)
+// RES(R143, RES_K(22)) -- part of final amp (not emulated)
+// RES(R144, RES_K(22)) -- part of final amp (not emulated)
+ RES(R145, RES_K(4.7))
+ RES(R146, RES_K(100))
+ RES(R147, RES_M(2.2))
+ RES(R148, RES_K(100))
+ RES(R149, RES_K(100))
+ RES(R150, RES_K(33))
+ RES(R151, RES_M(1))
+ RES(R152, RES_K(22))
+ RES(R153, RES_K(47))
+ RES(R154, RES_K(24))
+ RES(R155, RES_K(56))
+ RES(R156, RES_K(39))
+ RES(R157, RES_K(27))
+ RES(R158, RES_K(33))
+ RES(R159, RES_K(62))
+ RES(R160, RES_K(82))
+ RES(R161, RES_K(120))
+ RES(R162, RES_K(4.7))
+ RES(R163, RES_K(10))
+ RES(R164, RES_K(10))
+ RES(R165, RES_M(1))
+ RES(R166, RES_M(1))
+ RES(R167, RES_K(1))
+ RES(R168, RES_M(1))
+ RES(R169, RES_K(100))
+ RES(R170, RES_M(2.2))
+ RES(R171, RES_K(100))
+ RES(R172, RES_K(33))
+ RES(R173, RES_K(47))
+ RES(R174, RES_K(47))
+ RES(R175, RES_K(47))
+ RES(R176, RES_K(47))
+ RES(R177, RES_K(47))
+ RES(R178, RES_K(22))
+ RES(R179, RES_K(47))
+ RES(R180, RES_K(47))
+ RES(R181, RES_K(47))
+ RES(R182, RES_K(10))
+ RES(R183, RES_K(10))
+ RES(R184, RES_K(4.7))
+ RES(R185, RES_M(1))
+ RES(R186, RES_K(1))
+
+ CAP(C1, CAP_U(0.01))
+ CAP(C2, CAP_U(0.01))
+ CAP(C3, CAP_U(0.1))
+ CAP(C4, CAP_U(0.05))
+ CAP(C5, CAP_U(0.1))
+ CAP(C6, CAP_U(10))
+ CAP(C7, CAP_U(0.1))
+ CAP(C8, CAP_U(0.1))
+ CAP(C9, CAP_U(0.1))
+// CAP(C10, CAP_U(0.05))
+// CAP(C11, CAP_U(0.05))
+ CAP(C12, CAP_U(10))
+// CAP(C13, CAP_U(0.05))
+// CAP(C14, CAP_U(0.05))
+ CAP(C15, CAP_U(10))
+ CAP(C16, CAP_U(0.01))
+ CAP(C17, CAP_U(0.01))
+ CAP(C18, CAP_U(0.022))
+ CAP(C19, CAP_U(0.05))
+ CAP(C20, CAP_U(0.1))
+ CAP(C21, CAP_U(0.33))
+ CAP(C22, CAP_U(0.33))
+ CAP(C23, CAP_U(0.01))
+ CAP(C24, CAP_U(0.01))
+ CAP(C25, CAP_U(0.01))
+ CAP(C26, CAP_U(0.022))
+ CAP(C27, CAP_U(10))
+ CAP(C28, CAP_U(0.05))
+// CAP(C29, CAP_U(0.05))
+// CAP(C30, CAP_U(0.05))
+ CAP(C31, CAP_U(0.0047))
+ CAP(C32, CAP_U(0.05))
+ CAP(C33, CAP_U(10))
+ CAP(C34, CAP_U(10))
+ CAP(C35, CAP_U(0.1))
+ CAP(C36, CAP_U(0.0022))
+ CAP(C37, CAP_U(0.1))
+ CAP(C38, CAP_U(0.1))
+ CAP(C39, CAP_U(0.1))
+ CAP(C40, CAP_U(0.01))
+ CAP(C41, CAP_U(0.01))
+// CAP(C42, CAP_U(0.001))
+// CAP(C43, CAP_U(10))
+// CAP(C44, CAP_U(0.001))
+// CAP(C45, CAP_U(0.001))
+// CAP(C46, CAP_U(10))
+ CAP(C47, CAP_U(4.7))
+// CAP(C48, CAP_U(22)) -- part of final amp (not emulated)
+ CAP(C49, CAP_U(0.05))
+ CAP(C50, CAP_U(0.05))
+ CAP(C51, CAP_U(0.05))
+ CAP(C52, CAP_U(0.05))
+ CAP(C53, CAP_U(0.1))
+// CAP(C54, CAP_U(0.05))
+ CAP(C55, CAP_U(0.05))
+ CAP(C56, CAP_U(10))
+ CAP(C57, CAP_U(0.1))
+// CAP(C58, CAP_U(4.7)) -- part of final amp (not emulated)
+ CAP(C59, CAP_U(0.33))
+ CAP(C60, CAP_U(4.7))
+ CAP(C61, CAP_U(4.7))
+ CAP(C62, CAP_U(10))
+ CAP(C63, CAP_U(0.1))
+ CAP(C64, CAP_U(0.1))
+ CAP(C65, CAP_U(0.01))
+// CAP(C66, CAP_U(0.05))
+ CAP(C67, CAP_U(0.05))
+ CAP(C68, CAP_U(0.0047))
+ CAP(C69, CAP_U(4.7))
+ CAP(C70, CAP_U(0.1))
+ CAP(C71, CAP_U(0.022))
+ CAP(C72, CAP_U(0.05))
+// CAP(C73, CAP_U(0.05))
+ CAP(C74, CAP_U(0.05))
+ CAP(C75, CAP_U(0.05))
+ CAP(C76, CAP_U(0.022))
+ CAP(C77, CAP_U(0.0047))
+ CAP(C78, CAP_U(0.1))
+// CAP(C79, CAP_U(0.05))
+ CAP(C80, CAP_U(4.7))
+ CAP(C81, CAP_U(0.05))
+ CAP(C82, CAP_U(0.1))
+
+ D_1N5231(D1)
+ D_1N914(D2)
+ D_1N5231(D3)
+ D_1N5231(D4)
+ D_1N5231(D5)
+ D_1N5231(D6)
+ D_1N914(D7)
+ D_1N914(D8)
+ D_1N914(D9)
+ D_1N5231(D10)
+ D_1N914(D11)
+ D_1N914(D12)
+// D_1N914(D13) -- part of final amp (not emulated)
+ D_1N914(D14)
+ D_1N914(D15)
+ D_1N914(D16)
+ D_1N914(D17)
+ D_1N914(D18)
+ D_1N914(D19)
+ D_1N914(D20)
+ D_1N914(D21)
+ D_1N914(D22)
+ D_1N914(D23)
+ D_1N914(D24)
+ D_1N914(D25)
+ D_1N914(D26)
+ D_1N914(D27)
+ D_1N914(D28)
+ D_1N914(D29)
+ D_1N914(D30)
+ D_1N914(D31)
+
+ Q_2N4403(Q1)
+ Q_2N4403(Q2)
+ Q_2N4403(Q3)
+ Q_2N4093(Q4)
+ Q_2N4093(Q5)
+ Q_2N4093(Q6)
+ Q_2N4403(Q7)
+ Q_2N4403(Q8)
+ Q_2N4403(Q9)
+ Q_2N4403(Q10)
+
+ TL084_DIP(U1) // Op. Amp.
+ NET_C(U1.4, I_V12)
+ NET_C(U1.11, I_VM12)
+
+ TL084_DIP(U2) // Op. Amp.
+ NET_C(U2.4, I_V12)
+ NET_C(U2.11, I_VM12)
+
+ CD4017_DIP(U3) // Decade Counter/Divider
+ NET_C(U3.8, GND)
+ NET_C(U3.16, I_V12)
+
+ NE555_DIP(U4) // Timer
+
+ NE555_DIP(U5) // Timer
+
+ NE555_DIP(U6) // Timer
+
+ TL084_DIP(U7) // Op. Amp.
+ NET_C(U7.4, I_V12)
+ NET_C(U7.11, I_VM12)
+
+ MM5837_DIP(U8) // Noise Generator
+#if (UNDERCLOCK_NOISE_GEN)
+ // officially runs at 48-112kHz, but little noticeable difference
+ // in exchange for a big performance boost
+ PARAM(U8.FREQ, 12000)
+#endif
+
+ CD4011_DIP(U9) // Quad 2-Input NAND Gates
+ NET_C(U9.7, GND)
+ NET_C(U9.14, I_V12)
+
+ CD4011_DIP(U10) // Quad 2-Input NAND Gates
+ NET_C(U10.7, GND)
+ NET_C(U10.14, I_V12)
+
+ CD4011_DIP(U11) // Quad 2-Input NAND Gates
+ NET_C(U11.7, GND)
+ NET_C(U11.14, I_V12)
+
+ CD4024_DIP(U12) // 7-Stage Ripple Binary Counter
+ NET_C(U12.7, GND)
+ NET_C(U12.14, I_V12)
+
+ NE555_DIP(U13) // Timer
+
+ CD4024_DIP(U14) // 7-Stage Ripple Binary Counter
+ NET_C(U14.7, GND)
+ NET_C(U14.14, I_V12)
+
+ CD4017_DIP(U15) // Decade Counter/Divider
+ NET_C(U15.8, GND)
+ NET_C(U15.16, I_V12)
+
+ TL084_DIP(U16) // Op. Amp.
+ NET_C(U16.4, I_V12)
+ NET_C(U16.11, I_VM12)
+
+ NE555_DIP(U17) // Timer
+
+ NE555_DIP(U18) // Timer
+
+ CD4024_DIP(U19) // 7-Stage Ripple Binary Counter
+ NET_C(U19.7, GND)
+ NET_C(U19.14, I_V12)
+
+ NE555_DIP(U20) // Timer
+
+ CD4011_DIP(U21) // Quad 2-Input NAND Gates
+ NET_C(U21.7, GND)
+ NET_C(U21.14, I_V12)
+
+ TL084_DIP(U22) // Op. Amp.
+ NET_C(U22.4, I_V12)
+ NET_C(U22.11, I_VM12)
+
+ NE555_DIP(U23) // Timer
+
+ NE555_DIP(U24) // Timer
+
+ CD4011_DIP(U25) // Quad 2-Input NAND Gates
+ NET_C(U25.7, GND)
+ NET_C(U25.14, I_V12)
+
+ TTL_7407_DIP(U26) // Hex Buffers with High Votage Open-Collector Outputs
+ NET_C(U26.7, GND)
+ NET_C(U26.14, I_V5)
+
+ CD4011_DIP(U27) // Quad 2-Input NAND Gates
+ NET_C(U27.7, GND)
+ NET_C(U27.14, I_V12)
+
+ CD4024_DIP(U28) // 7-Stage Ripple Binary Counter
+ NET_C(U28.7, GND)
+ NET_C(U28.14, I_V12)
+
+ TTL_7407_DIP(U29) // Hex Buffers with High Votage Open-Collector Outputs
+ NET_C(U29.7, GND)
+ NET_C(U29.14, I_V5)
+
+ TTL_7406_DIP(U30) // Hex inverter -- currently using a clone of 7416, no open collector behavior
+ NET_C(U30.7, GND)
+ NET_C(U30.14, I_V5)
+
+ TTL_7406_DIP(U31) // Hex inverter -- currently using a clone of 7416, no open collector behavior
+ NET_C(U31.7, GND)
+ NET_C(U31.14, I_V5)
+
+// TTL_74LS374_DIP(U32) // Octal D-Type Transparent Latches And Edge-Triggered Flip-Flop
+// NET_C(U32.10, GND)
+// NET_C(U32.20, I_V5)
+
+// TTL_74LS374_DIP(U33) // Octal D-Type Transparent Latches And Edge-Triggered Flip-Flop
+// NET_C(U33.10, GND)
+// NET_C(U33.20, I_V5)
+
+// TTL_74LS00_DIP(U34) // Quad 4-Input NAND Gate
+// NET_C(U34.7, GND)
+// NET_C(U34.14, I_V5)
+
+// TTL_74LS30_DIP(U35) // 8-Input NAND Gate
+// NET_C(U35.7, GND)
+// NET_C(U35.14, I_V5)
+
+// TTL_74LS04_DIP(U36) // Hex Inverting Gates
+// NET_C(U36.7, GND)
+// NET_C(U36.14, I_V5)
+
+ NE555_DIP(U37) // Timer
+
+ NE555_DIP(U38) // Timer
+
+ //
+ // Sheet 7, top-left (SONAR)
+ //
+
+ NET_C(U1.3, GND)
+ NET_C(U1.2, D1.A, R4.1)
+ NET_C(U1.1, D1.K, R1.1)
+ NET_C(R1.2, R2.2, C1.1, C2.1)
+ NET_C(R2.1, GND)
+ NET_C(R4.2, R3.2, U1.7, C2.2, R5.2)
+ NET_C(C1.2, R3.1, U1.6)
+ NET_C(U1.5, GND)
+
+#if (SIMPLIFY_SONAR)
+ // sonar has 4 identical circuits; reduce the net size
+ // by only emulating one and multiplying it by 4
+ NET_C(U1.9, U1.10, U1.12, U1.13, GND)
+ NET_C(R36.1, R36.2, R37.1, R37.2, R38.1, R38.2, R39.1, R39.2, R40.1, R40.2, GND)
+ NET_C(C16.1, C16.2, C17.1, C17.2, GND)
+ NET_C(D4.A, D4.K, GND)
+
+ NET_C(U2.2, U2.3, U2.5, U2.6, GND)
+ NET_C(R62.1, R62.2, R63.1, R63.2, R64.1, R64.2, R65.1, R65.2, R66.1, R66.2, GND)
+ NET_C(C24.1, C24.2, C25.1, C25.2, GND)
+ NET_C(D6.A, D6.K, GND)
+
+ NET_C(U2.9, U2.10, U2.12, U2.13, GND)
+ NET_C(R91.1, R91.2, R92.1, R92.2, R93.1, R93.2, R94.1, R94.2, R95.1, R95.2, GND)
+ NET_C(C40.1, C40.2, C41.1, C41.2, GND)
+ NET_C(D10.A, D10.K, GND)
+
+ NET_C(R5.1, R114.1, Q3.B)
+#else
+ NET_C(U1.12, GND)
+ NET_C(U1.13, D4.A, R39.1)
+ NET_C(U1.14, D4.K, R36.1)
+ NET_C(R36.2, R37.2, C16.1, C17.1)
+ NET_C(R37.1, GND)
+ NET_C(R39.2, R38.2, U1.8, C17.2, R40.2)
+ NET_C(C16.2, R38.1, U1.9)
+ NET_C(U1.10, GND)
+
+ NET_C(U2.3, GND)
+ NET_C(U2.2, D6.A, R65.1)
+ NET_C(U2.14, D6.K, R62.1)
+ NET_C(R62.2, R63.2, C24.1, C25.1)
+ NET_C(R63.1, GND)
+ NET_C(R65.2, R64.2, U2.7, C25.2, R66.2)
+ NET_C(C24.2, R64.1, U2.6)
+ NET_C(U2.5, GND)
+
+ NET_C(U2.12, GND)
+ NET_C(U2.13, D10.A, R94.1)
+ NET_C(U2.14, D10.K, R91.1)
+ NET_C(R91.2, R92.2, C40.1, C41.1)
+ NET_C(R92.1, GND)
+ NET_C(R94.2, R93.2, U2.8, C41.2, R95.2)
+ NET_C(C40.2, R93.1, U2.9)
+ NET_C(U2.10, GND)
+
+ NET_C(R5.1, R40.1, R114.1, Q3.B, R95.1, R66.1)
+#endif
+
+ NET_C(R114.2, GND)
+ NET_C(Q3.E, Q2.E, Q1.C)
+ NET_C(Q1.B, R108.2, C47.2, R117.2)
+ NET_C(C47.1, R108.1, I_V12)
+ NET_C(I_V12, R109.1)
+ NET_C(R109.2, Q1.E)
+ NET_C(R117.1, D2.A)
+ NET_C(D2.K, U11.4, C4.2)
+ NET_C(C4.1, U11.2, R20.1)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_SONAR)
+ NET_C(D_SONAR.A, U11.2)
+ NET_C(D_SONAR.K, I_V12)
+#endif
+ NET_C(U11.5, U11.6, U11.3)
+ NET_C(U11.1, R21.1)
+ NET_C(I_SONAR, R21.1)
+ NET_C(R21.2, R20.2, I_V12)
+
+ NET_C(Q2.B, GND)
+ NET_C(Q2.C, R110.2, R111.2, U7.3)
+ NET_C(R110.1, GND)
+ NET_C(R111.1, R112.1, I_VM12)
+ NET_C(Q3.C, U7.2, R112.2, R113.1)
+ NET_C(R113.2, U7.1)
+ ALIAS(SONAR, U7.1)
+
+ //
+ // Sheet 7, middle-left (LASER-1)
+ //
+
+ NET_C(I_LASER_1, R146.1, U25.9)
+ NET_C(U25.8, C64.2, R138.1)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_LASER_1)
+ NET_C(D_LASER_1.A, U25.8)
+ NET_C(D_LASER_1.K, I_V12)
+#endif
+ NET_C(R146.2, R138.2, R134.2, R139.2, U24.8, C56.1, I_V12)
+ NET_C(U25.10, U25.5, U25.6, D11.K, U24.4)
+ NET_C(C64.1, U25.4, U19.2)
+ NET_C(D11.A, R107.1, C57.2)
+ NET_C(C57.1, Q10.C, C65.1, U24.1, GND)
+ NET_C(R107.2, Q10.B, R134.1)
+ NET_C(Q10.E, U24.5)
+#if (HLE_LASER_1_VCO)
+ //
+ // R2 = 0.98461: HP = (0.00000524285*A0) + 0.00000563193
+ // R2 = 0.99441: HP = (0.000000368659*A0*A0) + (0.00000116694*A0) + 0.0000155514
+ // R2 = 0.99797: HP = (0.000000154808*A0*A0*A0) - (0.00000213809*A0*A0) + (0.0000138122*A0) - 0.00000398935
+ // R2 = 0.99877: HP = (-0.0000000527853*A0*A0*A0*A0) + (0.00000128033*A0*A0*A0) - (0.0000107258*A0*A0) + (0.0000413916*A0) - 0.0000352437
+ // R2 = 0.99943: HP = (0.0000000343262*A0*A0*A0*A0*A0) - (0.00000096054*A0*A0*A0*A0) + (0.0000105481*A0*A0*A0) - (0.0000561978*A0*A0) + (0.000148191*A0) - 0.000131018
+ //
+ VARCLOCK(LASER1CLK, 1, "max(0.000001,min(0.1,(0.0000000343262*A0*A0*A0*A0*A0) - (0.00000096054*A0*A0*A0*A0) + (0.0000105481*A0*A0*A0) - (0.0000561978*A0*A0) + (0.000148191*A0) - 0.000131018))")
+ NET_C(LASER1CLK.GND, GND)
+ NET_C(LASER1CLK.VCC, I_V12)
+ NET_C(LASER1CLK.A0, Q10.E)
+ NET_C(LASER1CLK.Q, LASER1ENV.A1)
+ AFUNC(LASER1ENV, 2, "if(A0>6,A1,0)")
+ NET_C(LASER1ENV.A0, U25.10)
+ NET_C(LASER1ENV.Q, U19.1)
+ NET_C(U24.3, GND)
+ NET_C(U24.2, U24.6, R140.1, C65.2, GND)
+#else
+ NET_C(U24.3, U19.1)
+ NET_C(U24.2, U24.6, R140.1, C65.2)
+#endif
+ NET_C(R140.2, U24.7, R139.1)
+ NET_C(C56.2, GND)
+ NET_C(U19.12, R132.1)
+ NET_C(U19.11, R131.1)
+ NET_C(U19.9, R130.1)
+ NET_C(U19.6, R105.1)
+ NET_C(U19.4, R104.1)
+ NET_C(R104.2, R105.2, R130.2, R131.2, R132.2, C52.1)
+ ALIAS(LASER_1, C52.2)
+
+ //
+ // Sheet 7, bottom-left (LASER-2)
+ //
+
+ NET_C(I_LASER_2, R149.1, U25.12)
+ NET_C(U25.13, C63.2, R147.1)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_LASER_2)
+ NET_C(D_LASER_2.A, U25.13)
+ NET_C(D_LASER_2.K, I_V12)
+#endif
+ NET_C(R149.2, R147.2, R106.2, R145.2, U20.8, C62.1, I_V12)
+ NET_C(U25.11, U25.1, U25.2, D12.K, U20.4)
+ NET_C(C63.1, U25.3, U14.2)
+ NET_C(D12.A, R133.1, C53.2)
+ NET_C(C53.1, Q9.C, C68.1, U20.1, GND)
+ NET_C(R133.2, Q9.B, R106.1)
+ NET_C(Q9.E, U20.5)
+#if (HLE_LASER_2_VCO)
+ //
+ // R2 = 0.98942: HP = (0.00000251528*A0) + 0.00000244265
+ // R2 = 0.99596: HP = (0.000000160852*A0*A0) + (0.000000694298*A0) + 0.00000690896
+ // R2 = 0.99821: HP = (0.000000068284*A0*A0*A0) - (0.000000949931*A0*A0) + (0.00000630369*A0) - 0.00000175548
+ // R2 = 0.99896: HP = (-0.0000000291178*A0*A0*A0*A0) + (0.000000689145*A0*A0*A0) - (0.00000568073*A0*A0) + (0.0000214603*A0) - 0.0000188875
+ // R2 = 0.99937: HP = (0.0000000153499*A0*A0*A0*A0*A0) - (0.000000433800*A0*A0*A0*A0) + (0.00000480504*A0*A0*A0) - (0.0000257871*A0*A0) + (0.000068467*A0) - 0.0000608574
+ //
+ VARCLOCK(LASER2CLK, 1, "max(0.000001,min(0.1,(0.0000000153499*A0*A0*A0*A0*A0) - (0.000000433800*A0*A0*A0*A0) + (0.00000480504*A0*A0*A0) - (0.0000257871*A0*A0) + (0.000068467*A0) - 0.0000608574))")
+ NET_C(LASER2CLK.GND, GND)
+ NET_C(LASER2CLK.VCC, I_V12)
+ NET_C(LASER2CLK.A0, Q9.E)
+ NET_C(LASER2CLK.Q, LASER2ENV.A1)
+ AFUNC(LASER2ENV, 2, "if(A0>6,A1,0)")
+ NET_C(LASER2ENV.A0, U25.11)
+ NET_C(LASER2ENV.Q, U14.1)
+ NET_C(U20.3, GND)
+ NET_C(U20.2, U20.6, R137.1, C68.2, GND)
+#else
+ NET_C(U20.3, U14.1)
+ NET_C(U20.2, U20.6, R137.1, C68.2)
+#endif
+ NET_C(R137.2, U20.7, R145.1)
+ NET_C(C62.2, GND)
+ NET_C(U14.12, R125.1)
+ NET_C(U14.11, R126.1)
+ NET_C(U14.9, R128.1)
+ NET_C(U14.6, R129.1)
+ NET_C(U14.4, R127.1)
+ NET_C(R127.2, R129.2, R128.2, R126.2, R125.2, C51.1)
+ ALIAS(LASER_2, C51.2)
+
+ //
+ // Sheet 7, middle-top (REFILL)
+ //
+
+ NET_C(I_REFILL, U3.15, R59.1)
+ NET_C(R59.2, I_V12, R17.2)
+
+ // CD4011 oscillator: R18=2.7M, C3=0.1u, freq=2.664
+ CLOCK(OSC1, 2.664)
+ NET_C(OSC1.GND, GND)
+ NET_C(OSC1.VCC, I_V12)
+ NET_C(OSC1.Q, U3.14)
+ NET_C(R18.1, R18.2, C3.1, C3.2, U9.1, U9.2, U9.5, U9.6, GND)
+
+ NET_C(U3.3, R8.1)
+ NET_C(U3.2, R7.1)
+ NET_C(U3.4, R9.1)
+ NET_C(U3.7, R12.1)
+ NET_C(U3.10, R14.1)
+ NET_C(U3.1, R6.1)
+ NET_C(U3.5, R10.1)
+ NET_C(U3.6, R11.1)
+ NET_C(U3.9, R15.1)
+ NET_C(U3.11, R13.1)
+ NET_C(U3.13, GND)
+ NET_C(R17.1, R8.2, R7.2, R9.2, R12.2, R14.2, R6.2, R10.2, R11.2, R15.2, R13.2, R16.2)
+ NET_C(R16.1, Q7.B)
+
+ // CD4011 oscillator: R46=470k, C20=0.1u, freq=15.307
+ CLOCK(OSC2, 15.307)
+ NET_C(OSC2.GND, GND)
+ NET_C(OSC2.VCC, I_V12)
+ NET_C(OSC2.Q, U4.4, U9.12, U9.13)
+ NET_C(U9.11, U5.4)
+ NET_C(R46.1, R46.2, C20.1, C20.2, U9.8, U9.9, GND)
+
+ NET_C(U5.7, R67.1, R68.2)
+ NET_C(R68.1, U5.2, U5.6, C26.2)
+ NET_C(C26.1, GND, U5.1, C18.1, U4.1, Q7.C)
+ NET_C(U5.5, U4.5, Q7.E)
+ NET_C(R67.2, U5.8, R41.2, U4.8, I_V12)
+ NET_C(R41.1, R42.2, U4.7)
+ NET_C(R42.1, U4.2, U4.6, C18.2)
+ NET_C(U5.3, R69.2)
+ NET_C(U4.3, R43.2)
+ NET_C(R43.1, C49.1, R69.1, I_REFILL_Q)
+ ALIAS(REFILL, C49.2)
+
+ //
+ // Sheet 7, middle-bottom (ATTACK, RATE RESET)
+ //
+
+ NET_C(I_RATE_RESET, U15.15, R96.1)
+ NET_C(R96.2, I_V12)
+ NET_C(I_ATTACK_RATE, R148.1, U21.5)
+ NET_C(R148.2, R166.2, I_V12)
+ NET_C(U21.6, R166.1, C67.2)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_ATTACK_RATE)
+ NET_C(D_ATTACK_RATE.A, U21.6)
+ NET_C(D_ATTACK_RATE.K, I_V12)
+#endif
+ NET_C(C67.1, U21.3)
+ NET_C(U21.4, U21.1, U21.2, U15.14)
+
+ NET_C(U15.3, D23.A)
+ NET_C(D23.K, R161.1)
+ NET_C(U15.2, D22.A)
+ NET_C(D22.K, R160.1)
+ NET_C(U15.4, D21.A)
+ NET_C(D21.K, R159.1)
+ NET_C(U15.7, D17.A)
+ NET_C(D17.K, R155.1)
+ NET_C(U15.10, D15.A)
+ NET_C(D15.K, R153.1)
+ NET_C(U15.1, D18.A)
+ NET_C(D18.K, R156.1)
+ NET_C(U15.5, D20.A)
+ NET_C(D20.K, R158.1)
+ NET_C(U15.6, D19.A)
+ NET_C(D19.K, R157.1)
+ NET_C(U15.9, D16.A)
+ NET_C(D16.K, R154.1)
+ NET_C(U15.11, D14.A)
+ NET_C(D14.K, R152.1)
+ NET_C(U15.13, GND)
+ NET_C(R161.2, R160.2, R159.2, R155.2, R153.2, R156.2, R158.2, R157.2, R154.2, R152.2, R178.2, U16.6)
+
+ NET_C(I_WARP, R164.1)
+ NET_C(R164.2, R162.1, R163.2, U16.5)
+ NET_C(R162.2, I_V12)
+ NET_C(R163.1, GND)
+ NET_C(U16.7, R178.1)
+ ALIAS(V, U16.7)
+
+ //
+ // Sheet 7, top-right (EXPLOSIONS)
+ //
+
+ NET_C(I_SHORT_EXPL, R169.1, U27.2)
+ NET_C(R169.2, R185.2, I_V12)
+ NET_C(U27.1, R185.1, C81.2)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_SHORT_EXPL)
+ NET_C(D_SHORT_EXPL.A, U27.1)
+ NET_C(D_SHORT_EXPL.K, I_V12)
+#endif
+ NET_C(C81.1, U27.11)
+ NET_C(U27.13, U27.12, U27.3)
+ NET_C(U27.3, R184.1)
+ NET_C(R184.2, D31.A)
+ NET_C(D31.K, D30.A, R182.2, R183.2)
+ NET_C(R182.1, GND)
+ NET_C(D30.K, R180.1, R181.1, C80.1, D29.K)
+ NET_C(C80.2, GND)
+ NET_C(R180.2, U16.9, R179.1)
+ NET_C(R179.2, U16.8, R177.1)
+ NET_C(R181.2, U16.10, Q6.D, D26.K) // D and S swapped on schematics???
+ NET_C(Q6.G, C72.2, R151.2, Q5.G)
+ NET_C(R151.1, GND)
+ NET_C(C72.1, U8.3)
+ NET_C(U8.4, I_V12)
+ NET_C(U8.2, I_VM12)
+ NET_C(U8.1, GND)
+ NET_C(Q6.S, D26.A, GND)
+ NET_C(D29.A, D24.K, C69.1)
+ NET_C(C69.2, GND)
+ NET_C(R183.1, R186.2, U27.4, U27.8, U27.9, D28.K)
+ NET_C(R186.1, C75.1)
+ NET_C(C75.2, U21.8, U21.9, R168.2)
+ NET_C(R168.1, U21.11)
+ NET_C(I_LONG_EXPL, R171.1, U27.6)
+ NET_C(R171.2, R170.2, I_V12)
+ NET_C(R170.1, U27.5, C82.2)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_LONG_EXPL)
+ NET_C(D_LONG_EXPL.A, U27.5)
+ NET_C(D_LONG_EXPL.K, I_V12)
+#endif
+ NET_C(C82.1, U27.10)
+ NET_C(U21.12, U21.13, C74.1, R165.2)
+ NET_C(U21.10, C74.2, R167.1)
+ NET_C(R165.1, GND)
+ NET_C(R167.2, D24.A)
+ NET_C(R177.2, R176.1, C78.1)
+ NET_C(C78.2, U16.2, U16.1, C61.1)
+ NET_C(R176.2, U16.3, C77.2, C76.2)
+ ALIAS(EXPLOSIONS, C61.2)
+ NET_C(C77.1, GND)
+ NET_C(C76.1, D27.K, D28.A)
+ NET_C(D27.A, GND)
+
+ //
+ // Sheet 7, middle-right (ASTROIDS)
+ //
+
+ NET_C(I_ASTROIDS, R97.1, R174.1, R175.1)
+ NET_C(R97.2, I_V12)
+ NET_C(R174.2, U16.13, R173.1)
+ NET_C(R175.2, U16.12, Q5.D, D25.K) // D and S swapped on schematics???
+ NET_C(D25.A, Q5.S, GND)
+ NET_C(R173.2, U16.14, R172.1)
+ NET_C(R172.2, R150.1, C70.1)
+ NET_C(C70.2, U7.9, U7.8, R136.1)
+ NET_C(R150.2, C71.2, U7.10)
+ NET_C(C71.1, GND)
+ NET_C(R136.2, C59.2, C60.1)
+ NET_C(C59.1, GND)
+ ALIAS(ASTROIDS, C60.2)
+
+ //
+ // Sheet 7, bottom-right (mixer)
+ //
+
+ ALIAS(INVADER_1, R98.1)
+ ALIAS(INVADER_2, R99.1)
+ ALIAS(INVADER_3, R100.1)
+ ALIAS(INVADER_4, R101.1)
+ NET_C(R98.2, R99.2, R100.2, R101.2, C55.1)
+ NET_C(ASTROIDS, R121.1)
+ NET_C(EXPLOSIONS, R122.1)
+ ALIAS(BONUS, R118.1)
+ NET_C(REFILL, R119.1)
+ NET_C(LASER_1, R102.1)
+ NET_C(LASER_2, R103.1)
+ NET_C(SONAR, R120.1)
+ NET_C(C55.2, R121.2, R122.2, R118.2, R119.2, R102.2, R103.2, R120.2)
+ AFUNC(MUTEFUNC, 2, "if(A0>2.5,0,A1)")
+ NET_C(MUTEFUNC.A0, I_MUTE)
+ NET_C(MUTEFUNC.A1, R121.2)
+ ALIAS(OUTPUT, MUTEFUNC.Q)
+// ALIAS(OUTPUT, C55.2)
+
+ //
+ // Sheet 8, middle-top (INVADER_1)
+ //
+
+ NET_C(U22.10, GND)
+ NET_C(U22.9, D5.A, R29.1)
+ NET_C(R29.2, R55.2, U22.14, C21.2, R72.1)
+ NET_C(D5.K, U22.8, R58.1)
+ NET_C(R58.2, C22.1, R57.2, R56.2, C21.1)
+ NET_C(W, U30.5)
+ NET_C(U30.6, R57.1)
+ NET_C(R56.1, GND)
+ NET_C(U22.13, C22.2, R55.1)
+ NET_C(U22.12, GND)
+
+ NET_C(R85.1, U23.7, R86.2)
+ NET_C(R85.2, U23.8, R83.2, R84.2, R73.2, U18.8, I_V12)
+ NET_C(R86.1, U23.2, U23.6, C38.2)
+ NET_C(C38.1, U23.1, C37.1, C28.1, U18.1, GND)
+ NET_C(I_INVADER_1, U23.4, R73.1, U18.4)
+ NET_C(C28.2, U18.5)
+ NET_C(U23.3, U18.2)
+ NET_C(U23.5, R87.2)
+ NET_C(R87.1, V)
+ NET_C(R83.1, D9.A)
+ NET_C(D9.K, Q8.B, R72.2)
+ NET_C(Q8.E, R84.1)
+ NET_C(Q8.C, C37.2, U18.6, U18.7)
+ NET_C(U18.3, INVADER_1)
+
+ //
+ // Sheet 8, middle (INVADER_2)
+ //
+
+ NET_C(R81.2, R70.2, U13.8, C27.1, I_V12)
+ NET_C(C27.2, GND)
+ NET_C(R81.1, R82.2, U13.7)
+ NET_C(R82.1, U13.2, U13.6, C36.2)
+ NET_C(C36.1, U13.1, GND)
+ NET_C(U13.5, R71.2)
+ NET_C(R71.1, V)
+ NET_C(I_INVADER_2, U13.4, R70.1)
+ NET_C(U13.3, U12.1)
+ // CD4011 oscillator: R22=470k, C5=0.1u, freq=15.3Hz
+ CLOCK(OSC3, 15.3)
+ NET_C(OSC3.GND, GND)
+ NET_C(OSC3.VCC, I_V12)
+ NET_C(OSC3.Q, U12.2)
+ NET_C(R22.1, R22.2, C5.1, C5.2, U11.8, U11.9, U11.12, U11.13, GND)
+ NET_C(U12.12, R48.1)
+ NET_C(U12.11, R49.1)
+ NET_C(U12.9, R50.1)
+ NET_C(U12.6, R47.1)
+ NET_C(R47.2, R50.2, R49.2, R48.2)
+ NET_C(R48.2, INVADER_2)
+
+ //
+ // Sheet 8, middle-bottom (INVADER_4)
+ //
+
+ NET_C(R89.2, U37.4, U37.8, C15.1, R60.2, R88.2, U38.8, I_V12)
+ NET_C(R89.1, U37.7, R90.2)
+ NET_C(R90.1, U37.2, U37.6, C39.2)
+ NET_C(C39.1, U37.1, C23.1, U38.1, GND)
+ NET_C(U37.5, R35.1)
+ NET_C(R35.2, V, R34.1)
+ NET_C(C15.2, GND)
+ NET_C(U37.3, U28.1)
+ NET_C(U28.2, U28.5)
+ NET_C(U28.12, R31.1)
+ NET_C(U28.11, R32.1)
+ NET_C(U28.9, R33.1)
+ NET_C(U28.6, R30.1)
+ NET_C(R31.2, R32.2, R33.2, R30.2, R34.2, U38.5)
+ NET_C(U38.2, U38.6, C23.2, R61.1)
+ NET_C(R61.2, U38.7, R60.1)
+ NET_C(U38.4, R88.1, I_INVADER_4)
+ NET_C(INVADER_4, U38.3)
+
+ //
+ // Sheet 8, middle-bottom (BONUS)
+ //
+
+ NET_C(I_BONUS, R45.1, U10.6)
+ NET_C(C34.1, R77.2, I_V12)
+ NET_C(R45.2, R44.2, R74.2, U6.4, U6.8, C33.1, I_V12)
+
+ NET_C(R44.1, U10.5, C19.1)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_BONUS)
+ NET_C(D_BONUS.A, U10.5)
+ NET_C(D_BONUS.K, I_V12)
+#endif
+ NET_C(U10.4, U10.1, U10.2)
+ NET_C(C19.2, U10.3, D7.K)
+ NET_C(D7.A, R78.1)
+ NET_C(R78.2, R77.1, C34.2, R76.1)
+ // CD4011 oscillator: R80=1M, C35=0.1, freq=7.19Hz
+ CLOCK(OSC4, 7.19)
+ NET_C(OSC4.GND, GND)
+ NET_C(OSC4.VCC, I_V12)
+ NET_C(OSC4.Q, R79.1)
+ NET_C(R80.1, R80.2, C35.1, C35.2, U10.8, U10.9, U10.12, U10.13, GND)
+ NET_C(R79.2, R74.1, R75.2, U6.7)
+ NET_C(R75.1, U6.2, U6.6, C31.2)
+ NET_C(C31.1, C32.1, U6.1, GND)
+ NET_C(C32.2, U6.5)
+ NET_C(R76.2, D8.K, C50.1)
+ NET_C(U6.3, D8.A)
+ NET_C(C33.2, GND)
+ NET_C(BONUS, C50.2)
+
+ //
+ // Sheet 8, top-right (INVADER_3)
+ //
+
+ NET_C(U22.5, GND)
+ NET_C(U22.6, D3.A, R25.1)
+ NET_C(R25.2, C12.2, R24.2, U22.1, C8.2)
+ NET_C(D3.K, U22.7, R26.1)
+ NET_C(W, U30.9)
+ NET_C(U30.8, R28.1)
+ NET_C(R28.2, R26.2, C9.1, R27.2, C8.1)
+ NET_C(R27.1, GND)
+ NET_C(C9.2, U22.2, R24.1)
+ NET_C(U22.3, GND)
+ NET_C(C12.1, R54.1)
+ NET_C(R54.2, R53.1, U17.5)
+ NET_C(R53.2, V)
+ NET_C(U17.1, C7.1, GND)
+ NET_C(C7.2, U17.2, U17.6, R52.1)
+ NET_C(R52.2, U17.7, R51.1)
+ NET_C(R51.2, R23.2, U17.8, C6.1, I_V12)
+ NET_C(R23.1, U17.4, I_INVADER_3)
+ NET_C(C6.2, GND)
+ NET_C(INVADER_3, U17.3)
+
+ //
+ // Unconnected inputs
+ //
+
+ NET_C(GND, U7.5, U7.6, U7.12, U7.13)
+ NET_C(GND, U26.13)
+ NET_C(GND, U29.1, U29.3, U29.13)
+ NET_C(GND, U30.1, U30.11)
+
+ //
+ // Unconnected outputs
+ //
+
+#if (ENABLE_FRONTIERS)
+#define RXX 192
+ OPTIMIZE_FRONTIER(INVADER_1, RES_M(1), RXX)
+ OPTIMIZE_FRONTIER(INVADER_2, RES_M(1), RXX)
+ OPTIMIZE_FRONTIER(INVADER_3, RES_M(1), RXX)
+ OPTIMIZE_FRONTIER(INVADER_4, RES_M(1), RXX)
+
+ OPTIMIZE_FRONTIER(C50.1, RES_M(10), RXX)
+ OPTIMIZE_FRONTIER(C60.1, RES_M(10), RXX) // this is a big one
+ OPTIMIZE_FRONTIER(C61.1, RES_M(10), RXX)
+#endif
+
+NETLIST_END()
diff --git a/src/mame/audio/nl_astrob.h b/src/mame/audio/nl_astrob.h
new file mode 100644
index 00000000000..952dad78bfa
--- /dev/null
+++ b/src/mame/audio/nl_astrob.h
@@ -0,0 +1,10 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+#ifndef MAME_AUDIO_NL_ASTROB_H
+#define MAME_AUDIO_NL_ASTROB_H
+
+#pragma once
+
+NETLIST_EXTERNAL(astrob)
+
+#endif // MAME_AUDIO_NL_ASTROB_H
diff --git a/src/mame/audio/nl_cinemat_common.h b/src/mame/audio/nl_cinemat_common.h
index 1b2079b79b1..7533acd56da 100644
--- a/src/mame/audio/nl_cinemat_common.h
+++ b/src/mame/audio/nl_cinemat_common.h
@@ -71,7 +71,7 @@
// models copied from https://www.diodes.com/assets/Spice-Models/Discrete-Prodcut-Groups/Zener-Diodes.txt
#define D_1N914(name) DIODE(name, "1N914")
#define D_1N914B(name) DIODE(name, "1N914")
-#define D_1N5236B(name) DIODE(name, "D(BV=7.5 IS=27.5p RS=33.8 N=1.10 CJO=58.2p VJ=0.750 M=0.330 TT=50.1n)")
+#define D_1N5236B(name) ZDIODE(name, "D(BV=7.5 IS=27.5p RS=33.8 N=1.10 CJO=58.2p VJ=0.750 M=0.330 TT=50.1n)")
#define D_1N5240(name) ZDIODE(name, "D(BV=10 IS=14.4p RS=32.0 N=1.10 CJO=24.1p VJ=0.750 M=0.330 TT=50.1n)")
#define D_1N5240B(name) ZDIODE(name, "D(BV=10 IS=14.4p RS=32.0 N=1.10 CJO=24.1p VJ=0.750 M=0.330 TT=50.1n)")
diff --git a/src/mame/audio/nl_elim.cpp b/src/mame/audio/nl_elim.cpp
new file mode 100644
index 00000000000..1727de5c46f
--- /dev/null
+++ b/src/mame/audio/nl_elim.cpp
@@ -0,0 +1,1225 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+
+//NL_CONTAINS elim zektor
+
+//
+// Netlist for Eliminator/Zektor
+//
+// Derived from the schematics in the Eliminator and Zektor manuals.
+//
+// Known problems/issues:
+//
+// * The noise signal (WBN) is connected into the TORPEDO_2 sound
+// but seems to make no audible difference, either in the
+// simulation or in recordings. Disabling it gives a nice speedup.
+//
+// * Torpedo sounds don't retrigger until they're complete. This means
+// you can fire several times before the next firing sound triggers.
+// In recordings of games this doesn't appear to be the case.
+//
+
+#include "netlist/devices/net_lib.h"
+#include "nl_elim.h"
+
+
+//
+// Optimizations
+//
+
+#define UNDERCLOCK_NOISE_GEN (1)
+#define HLE_BACKGROUND_VCO (1)
+#define HLE_TORPEDO1_VCO (1)
+#define HLE_TORPEDO2_VCO (1)
+#define HLE_SKITTER_VCO (1)
+#define ENABLE_FRONTIERS (1)
+
+
+
+//
+// Hacks
+//
+
+#define ADD_CLIPPING_DIODES (1)
+#define DISABLE_TORPEDO2_NOISE (1)
+
+
+
+//
+// Initial compilation includes this section.
+//
+
+#ifndef SOUND_VARIANT
+
+
+#define D_1N914(name) DIODE(name, "1N914")
+#define D_1N4002(name) DIODE(name, "D(IS=65.4p RS=42.2m BV=100 IBV=5.00u CJO=14.8p M=0.333 N=1.36 TT=2.88u)")
+
+// SPICE model taken from https://www.onsemi.com/support/design-resources/models?rpn=2N4403
+#define Q_2N4403(name) QBJT_EB(name, "PNP(Is=650.6E-18 Xti=3 Eg=1.11 Vaf=115.7 Bf=216.2 Ne=1.829 Ise=58.72f Ikf=1.079 Xtb=1.5 Br=3.578 Nc=2 Isc=0 Ikr=0 Rc=.715 Cjc=14.76p Mjc=.5383 Vjc=.75 Fc=.5 Cje=19.82p Mje=.3357 Vje=.75 Tr=111.6n Tf=603.7p Itf=.65 Vtf=5 Xtf=1.7 Rb=10)")
+
+#define LM555_DIP NE555_DIP
+#define LM566_DIP NE566_DIP
+
+#define TTL_74LS00_DIP TTL_7400_DIP
+
+//
+// DIP mappings use the submodels below for CA3080
+//
+#define CA3080_DIP(name) SUBMODEL(_CA3080_FAST_DIP, name)
+static NETLIST_START(_CA3080_FAST_DIP)
+ ALIAS(2, F.A0) // -
+ ALIAS(3, F.A1) // +
+ ALIAS(4, F.A2) // V-
+ ALIAS(5, RIABC.1) // IB
+ ALIAS(6, VO.OP) // FIXME
+ ALIAS(7, F.A4) // V+
+
+ RES(RI, 26000)
+ NET_C(RI.1, F.A0)
+ NET_C(RI.2, F.A1)
+ // Delivers I0
+ AFUNC(F, 5, "max(-0.5e-3, min(0.5e-3, 19.2 * (A3 - A2) * A0))")
+ RES(RIABC, 1)
+ NET_C(RIABC.2, F.A2)
+ NET_C(RIABC.1, F.A3) // IB
+ VCCS(VO, 1)
+ ANALOG_INPUT(XGND, 0)
+ NET_C(XGND, VO.IN, VO.ON) // FIXME: assume symmetric supply
+ NET_C(F.Q, VO.IP)
+NETLIST_END()
+
+
+
+//
+// Now include ourselves twice, once for Eliminator and
+// once for Zektor
+//
+
+#define VARIANT_ELIMINATOR 0
+#define VARIANT_ZEKTOR 1
+
+#define SOUND_VARIANT (VARIANT_ELIMINATOR)
+#include "nl_elim.cpp"
+
+#undef SOUND_VARIANT
+#define SOUND_VARIANT (VARIANT_ZEKTOR)
+#include "nl_elim.cpp"
+
+
+#else
+
+
+//
+// Main netlist
+//
+
+#if (SOUND_VARIANT == VARIANT_ELIMINATOR)
+NETLIST_START(elim)
+#else // (SOUND_VARIANT == VARIANT_ZEKTOR)
+NETLIST_START(zektor)
+#endif
+
+ SOLVER(Solver, 1000)
+ PARAM(Solver.DYNAMIC_TS, 1)
+ PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 2e-5)
+
+ // Overwrite model - the default model uses minimum datasheet
+ // specifications for 5V. These are for 10V and thus closer to the
+ // 12V used in this circuit.
+ NET_MODEL("CD4XXX FAMILY(TYPE=CMOS IVL=0.3 IVH=0.7 OVL=0.05 OVH=0.05 ORL=384 ORH=384)")
+
+ LOCAL_SOURCE(_CA3080_FAST_DIP)
+
+// TTL_INPUT(I_LO_D0, 0)
+ TTL_INPUT(I_LO_D1, 0)
+ ALIAS(I_FIREBALL, I_LO_D1)
+ TTL_INPUT(I_LO_D2, 0)
+ ALIAS(I_EXPLOSION_1, I_LO_D2)
+ TTL_INPUT(I_LO_D3, 0)
+ ALIAS(I_EXPLOSION_2, I_LO_D3)
+ TTL_INPUT(I_LO_D4, 0)
+ ALIAS(I_EXPLOSION_3, I_LO_D4)
+ TTL_INPUT(I_LO_D5, 0)
+ ALIAS(I_BOUNCE, I_LO_D5)
+ TTL_INPUT(I_LO_D6, 0)
+ ALIAS(I_TORPEDO_1, I_LO_D6)
+ TTL_INPUT(I_LO_D7, 0)
+ ALIAS(I_TORPEDO_2, I_LO_D7)
+
+ NET_C(GND, I_LO_D1.GND, I_LO_D2.GND, I_LO_D3.GND, I_LO_D4.GND, I_LO_D5.GND, I_LO_D6.GND, I_LO_D7.GND)
+ NET_C(I_V5, I_LO_D1.VCC, I_LO_D2.VCC, I_LO_D3.VCC, I_LO_D4.VCC, I_LO_D5.VCC, I_LO_D6.VCC, I_LO_D7.VCC)
+
+ TTL_INPUT(I_HI_D0, 0)
+ ALIAS(I_THRUST_LOW, I_HI_D0)
+ TTL_INPUT(I_HI_D1, 0)
+ ALIAS(I_THRUST_HI, I_HI_D1)
+ TTL_INPUT(I_HI_D2, 0)
+ ALIAS(I_THRUST_LSB, I_HI_D2)
+ TTL_INPUT(I_HI_D3, 0)
+ ALIAS(I_THRUST_MSB, I_HI_D3)
+ TTL_INPUT(I_HI_D4, 0)
+ ALIAS(I_SKITTER, I_HI_D4)
+ TTL_INPUT(I_HI_D5, 0)
+ ALIAS(I_ENEMY_SHIP, I_HI_D5)
+ TTL_INPUT(I_HI_D6, 0)
+ ALIAS(I_BACKGROUND_LSB, I_HI_D6)
+ TTL_INPUT(I_HI_D7, 0)
+ ALIAS(I_BACKGROUND_MSB, I_HI_D7)
+
+ NET_C(GND, I_HI_D0.GND, I_HI_D1.GND, I_HI_D2.GND, I_HI_D3.GND, I_HI_D4.GND, I_HI_D5.GND, I_HI_D6.GND, I_HI_D7.GND)
+ NET_C(I_V5, I_HI_D0.VCC, I_HI_D1.VCC, I_HI_D2.VCC, I_HI_D3.VCC, I_HI_D4.VCC, I_HI_D5.VCC, I_HI_D6.VCC, I_HI_D7.VCC)
+
+ RES(R_PSG_1, 1000)
+ RES(R_PSG_2, 1000)
+ RES(R_PSG_3, 1000)
+ NET_C(I_V5, R_PSG_1.1, R_PSG_2.1, R_PSG_3.1)
+
+ ANALOG_INPUT(I_V5, 5)
+ ANALOG_INPUT(I_V12, 12)
+ ANALOG_INPUT(I_VM12, -12)
+
+ //
+ // Part differences between Eliminator and Zektor
+ //
+ // Ref Des ELIMINATOR ZEKTOR
+ // R5 10K 4.7K
+ // R9 33K 12K
+ // R71 270K 100K
+ // R79 2 MEG unused
+ // R122 220K 390K
+ // R132 220K 100K
+ // C9 0.01uF 0.0047uF
+ // C46 0.022uF 0.047uF
+ //
+
+// RES(R1, RES_K(100)) -- part of final amp (not emulated)
+// RES(R2, RES_M(1)) -- part of final amp (not emulated)
+// RES(R3, RES_K(22)) -- part of final amp (not emulated)
+// RES(R4, RES_K(2.2)) -- part of final amp (not emulated)
+#if (SOUND_VARIANT == VARIANT_ELIMINATOR)
+// RES(R5, RES_K(10)) -- part of final amp (not emulated)
+#else // (SOUND_VARIANT == VARIANT_ZEKTOR)
+// RES(R5, RES_K(4.7)) -- part of final amp (not emulated)
+#endif
+ RES(R6, RES_K(220))
+ RES(R7, RES_K(220))
+ RES(R8, RES_K(10))
+#if (SOUND_VARIANT == VARIANT_ELIMINATOR)
+ RES(R9, RES_K(33))
+#else // (SOUND_VARIANT == VARIANT_ZEKTOR)
+ RES(R9, RES_K(12))
+#endif
+ RES(R10, RES_K(10))
+// RES(R11, RES_K(2.2)) -- part of final amp (not emulated)
+// RES(R12, RES_M(1)) -- part of final amp (not emulated)
+// RES(R13, RES_K(330)) -- part of final amp (not emulated)
+ RES(R14, RES_K(470))
+ RES(R15, RES_K(100))
+ RES(R16, RES_K(100))
+ RES(R17, RES_K(10))
+ RES(R18, RES_K(10))
+ RES(R19, RES_K(1))
+ RES(R20, RES_K(10))
+ RES(R21, RES_K(100))
+ RES(R22, RES_K(10))
+ RES(R23, RES_K(4.7))
+// R24??
+ RES(R25, RES_K(220))
+ RES(R26, RES_K(470))
+ RES(R27, RES_K(470))
+ RES(R28, RES_K(33))
+ RES(R29, RES_K(68))
+ RES(R30, RES_K(22))
+ RES(R31, RES_K(1))
+ RES(R32, RES_K(47))
+ RES(R33, RES_K(82))
+ RES(R34, RES_K(22))
+ RES(R35, RES_K(1))
+ RES(R36, RES_M(1.5))
+ RES(R37, RES_K(6.8))
+ RES(R38, RES_K(33))
+ RES(R39, RES_K(22))
+ RES(R40, RES_K(1))
+ RES(R41, RES_M(2.2))
+ RES(R42, RES_M(2.2))
+ RES(R43, RES_K(1))
+ RES(R44, RES_K(10))
+ RES(R45, RES_K(47))
+ RES(R46, RES_K(22))
+ RES(R47, RES_K(2))
+ RES(R48, RES_K(6.8))
+ RES(R49, RES_K(33))
+ RES(R50, RES_K(22))
+ RES(R51, RES_K(1))
+ RES(R52, RES_K(1))
+ RES(R53, RES_K(1))
+ RES(R54, RES_K(2))
+ RES(R55, RES_K(1))
+ RES(R56, RES_K(1))
+ RES(R57, RES_K(1))
+ RES(R58, RES_K(33))
+ RES(R59, RES_K(2))
+ RES(R60, RES_K(10))
+ RES(R61, RES_K(47))
+ RES(R62, RES_K(220))
+ RES(R63, RES_K(1))
+ RES(R64, RES_K(150))
+ RES(R65, RES_K(390))
+ RES(R66, RES_K(33))
+ RES(R67, RES_K(100))
+ RES(R68, RES_K(100))
+ RES(R69, RES_K(1))
+ RES(R70, RES_K(470))
+#if (SOUND_VARIANT == VARIANT_ELIMINATOR)
+ RES(R71, RES_K(270))
+#else // (SOUND_VARIANT == VARIANT_ZEKTOR)
+ RES(R71, RES_K(100))
+#endif
+ RES(R72, RES_K(1))
+ RES(R73, RES_K(680))
+ RES(R74, RES_K(390))
+ RES(R75, RES_K(150))
+ RES(R76, RES_K(10))
+ RES(R77, RES_K(10))
+ RES(R78, RES_K(10))
+#if (SOUND_VARIANT == VARIANT_ELIMINATOR)
+ RES(R79, RES_M(2))
+#endif
+ RES(R80, RES_K(1))
+ RES(R81, RES_M(1.5))
+ RES(R82, 470)
+ RES(R83, 470)
+ RES(R84, RES_K(2.2))
+ RES(R85, RES_K(2.2))
+ RES(R86, RES_K(2.2))
+ RES(R87, RES_K(2.2))
+ RES(R88, RES_K(2.2))
+ RES(R89, RES_K(2.2))
+ RES(R90, RES_K(15))
+ RES(R91, RES_M(1))
+ RES(R92, RES_K(22))
+ RES(R93, RES_M(1))
+ RES(R94, RES_K(10))
+ RES(R95, RES_K(10))
+ RES(R96, RES_K(22))
+ RES(R97, RES_K(39))
+ RES(R98, RES_K(82))
+ RES(R99, RES_K(10))
+ RES(R100, RES_K(10))
+ RES(R101, 910)
+ RES(R102, RES_K(6.8))
+ RES(R103, RES_K(9.1)) // RES_K(2.2))
+ RES(R104, RES_K(15))
+ RES(R105, RES_K(10))
+ RES(R106, RES_K(680))
+ RES(R107, RES_K(4.7))
+ RES(R108, RES_K(4.7))
+ RES(R109, RES_K(2.2))
+ RES(R110, RES_K(2.2))
+ RES(R111, RES_K(100))
+ RES(R112, RES_M(2.2))
+ RES(R113, RES_M(1))
+ RES(R114, RES_K(100))
+ RES(R115, RES_M(1))
+ RES(R116, RES_M(1))
+ RES(R117, RES_M(1))
+ RES(R118, RES_K(100))
+ RES(R119, RES_K(100))
+ RES(R120, RES_K(100))
+ RES(R121, RES_M(2.2))
+#if (SOUND_VARIANT == VARIANT_ELIMINATOR)
+ RES(R122, RES_K(220))
+#else // (SOUND_VARIANT == VARIANT_ZEKTOR)
+ RES(R122, RES_K(390))
+#endif
+ RES(R123, RES_K(100))
+ RES(R124, RES_M(2.2))
+ RES(R125, RES_K(100))
+ RES(R126, RES_K(10))
+ RES(R127, RES_K(22))
+ RES(R128, RES_K(39))
+ RES(R129, RES_K(82))
+ RES(R130, RES_K(22))
+ RES(R131, RES_K(1))
+#if (SOUND_VARIANT == VARIANT_ELIMINATOR)
+ RES(R132, RES_K(220))
+#else // (SOUND_VARIANT == VARIANT_ZEKTOR)
+ RES(R132, RES_K(100))
+#endif
+ RES(R133, 680)
+ RES(R134, RES_K(10))
+ RES(R135, RES_K(10))
+ RES(R136, RES_K(680))
+ RES(R137, RES_K(10))
+ RES(R138, RES_K(10))
+ RES(R139, RES_K(330))
+ RES(R140, RES_K(270))
+ RES(R141, RES_K(220))
+ RES(R142, RES_K(330))
+ RES(R143, RES_K(680))
+ RES(R144, RES_K(100))
+ RES(R145, RES_K(68))
+ RES(R146, RES_K(22))
+ RES(R147, RES_K(2.2))
+
+// CAP(C1, CAP_U(4.7)) -- part of final amp (not emulated)
+// CAP(C2, CAP_U(0.1))
+// CAP(C3, CAP_U(0.1))
+// CAP(C4, CAP_U(10)) -- part of final amp (not emulated)
+ CAP(C5, CAP_U(0.1))
+ CAP(C6, CAP_U(0.1))
+ CAP(C7, CAP_U(0.001))
+ CAP(C8, CAP_U(10))
+#if (SOUND_VARIANT == VARIANT_ELIMINATOR)
+ CAP(C9, CAP_U(0.01))
+#else // (SOUND_VARIANT == VARIANT_ZEKTOR)
+ CAP(C9, CAP_U(0.0047))
+#endif
+ CAP(C10, CAP_U(0.068))
+ CAP(C11, CAP_U(0.068))
+ CAP(C12, CAP_U(0.1))
+ CAP(C13, CAP_U(0.1))
+ CAP(C14, CAP_U(0.1))
+ CAP(C15, CAP_U(0.068))
+ CAP(C16, CAP_U(0.068))
+ CAP(C17, CAP_U(0.068))
+ CAP(C18, CAP_U(0.068))
+ CAP(C19, CAP_U(0.068))
+ CAP(C20, CAP_U(0.068))
+ CAP(C21, CAP_U(2.2))
+// CAP(C22, CAP_U(0.1))
+// CAP(C23, CAP_U(0.1))
+// CAP(C24, CAP_U(0.1))
+// CAP(C25, CAP_U(0.1))
+// CAP(C26, CAP_U(0.1))
+// CAP(C27, CAP_U(0.1))
+ CAP(C28, CAP_U(0.1))
+ CAP(C29, CAP_U(0.1))
+ CAP(C30, CAP_U(0.022))
+// CAP(C31, CAP_U(0.1))
+// CAP(C32, CAP_U(0.1))
+ CAP(C33, CAP_U(0.1))
+ CAP(C34, CAP_U(0.1))
+ CAP(C35, CAP_U(1))
+ CAP(C36, CAP_U(2.2))
+ CAP(C37, CAP_U(10))
+ CAP(C38, CAP_U(4.7))
+ CAP(C39, CAP_U(0.1))
+// CAP(C40, CAP_U(0.1))
+// CAP(C41, CAP_U(0.1))
+// C42??
+ CAP(C43, CAP_U(0.033))
+ CAP(C44, CAP_U(0.1))
+ CAP(C45, CAP_U(0.1))
+#if (SOUND_VARIANT == VARIANT_ELIMINATOR)
+ CAP(C46, CAP_U(0.022))
+#else // (SOUND_VARIANT == VARIANT_ZEKTOR)
+ CAP(C46, CAP_U(0.047))
+#endif
+ CAP(C47, CAP_U(0.047))
+ CAP(C48, CAP_U(0.05))
+ CAP(C49, CAP_U(0.1))
+ CAP(C50, CAP_U(0.05))
+ CAP(C51, CAP_U(0.05))
+ CAP(C52, CAP_U(0.05))
+ CAP(C53, CAP_U(0.1))
+ CAP(C54, CAP_U(0.1))
+ CAP(C55, CAP_U(0.1))
+ CAP(C56, CAP_U(33))
+ CAP(C57, CAP_U(0.1))
+ CAP(C58, CAP_U(0.1))
+ CAP(C59, CAP_U(0.1))
+ CAP(C60, CAP_U(0.001))
+ CAP(C61, CAP_U(0.068))
+// CAP(C62, CAP_U(0.1))
+ CAP(C63, CAP_P(100))
+ CAP(C64, CAP_U(0.1))
+ CAP(C65, CAP_U(0.01))
+ CAP(C66, CAP_U(0.022))
+ CAP(C67, CAP_U(0.047))
+ CAP(C68, CAP_U(0.01))
+ CAP(C69, CAP_U(0.1))
+// CAP(C70, CAP_U(0.1))
+// CAP(C71, CAP_U(0.1))
+// CAP(C72, CAP_U(0.1))
+// CAP(C73, CAP_U(10))
+// CAP(C74, CAP_U(0.1))
+ CAP(C75, CAP_U(0.1))
+ CAP(C76, CAP_U(0.1))
+ CAP(C77, CAP_U(0.1))
+
+ D_1N914(D1)
+ D_1N914(D2)
+ D_1N914(D3)
+ D_1N914(D4)
+ D_1N914(D5)
+ D_1N914(D6)
+ D_1N914(D7)
+ D_1N4002(D8)
+
+// Q_2N4093(Q1) -- part of final amp (not emulated)
+ Q_2N4403(Q2)
+ Q_2N4403(Q3)
+ Q_2N4403(Q4)
+ Q_2N4403(Q5)
+ Q_2N4403(Q6)
+ Q_2N4403(Q7)
+ Q_2N4403(Q8)
+ Q_2N4403(Q9)
+ Q_2N4403(Q10)
+ Q_2N4403(Q11)
+
+ TL081_DIP(U1) // Op. Amp.
+ NET_C(U1.7, I_V12)
+ NET_C(U1.4, I_VM12)
+
+// TL082_DIP(U2) // Op. Amp. -- part of final amp (not emulated)
+// NET_C(U2.8, I_V12)
+// NET_C(U2.4, I_VM12)
+
+ TL081_DIP(U3) // Op. Amp.
+ NET_C(U3.7, I_V12)
+ NET_C(U3.4, I_VM12)
+
+ MM5837_DIP(U4) // Noise Generator
+#if (UNDERCLOCK_NOISE_GEN)
+ PARAM(U4.FREQ, 24000)
+#endif
+
+ LM555_DIP(U5) // Timer
+
+ CA3080_DIP(U6) // Op. Amp.
+ NET_C(U6.4, I_VM12)
+ NET_C(U6.7, I_V12)
+
+ CA3080_DIP(U7) // Op. Amp.
+ NET_C(U7.4, I_VM12)
+ NET_C(U7.7, I_V12)
+
+ CA3080_DIP(U8) // Op. Amp.
+ NET_C(U8.4, I_VM12)
+ NET_C(U8.7, I_V12)
+
+ CA3080_DIP(U9) // Op. Amp.
+ NET_C(U9.4, I_VM12)
+ NET_C(U9.7, I_V12)
+
+ CA3080_DIP(U10) // Op. Amp.
+ NET_C(U10.4, I_VM12)
+ NET_C(U10.7, I_V12)
+
+ CA3080_DIP(U11) // Op. Amp.
+ NET_C(U11.4, I_VM12)
+ NET_C(U11.7, I_V12)
+
+ TL081_DIP(U12) // Op. Amp.
+ NET_C(U12.7, I_V12)
+ NET_C(U12.4, I_VM12)
+
+ LM555_DIP(U13) // Timer
+
+ CA3080_DIP(U14) // Op. Amp.
+ NET_C(U14.4, I_VM12)
+ NET_C(U14.7, I_V12)
+
+ CA3080_DIP(U15) // Op. Amp.
+ NET_C(U15.4, I_VM12)
+ NET_C(U15.7, I_V12)
+
+ TL082_DIP(U16) // Op. Amp.
+ NET_C(U16.8, I_V12)
+ NET_C(U16.4, I_VM12)
+
+ CD4011_DIP(U17) // Quad 2-Input NAND Gates
+ NET_C(U17.7, GND)
+ NET_C(U17.14, I_V12)
+
+ CD4011_DIP(U18) // Quad 2-Input NAND Gates
+ NET_C(U18.7, GND)
+ NET_C(U18.14, I_V12)
+
+ CD4011_DIP(U19) // Quad 2-Input NAND Gates
+ NET_C(U19.7, GND)
+ NET_C(U19.14, I_V12)
+
+ TL082_DIP(U20) // Op. Amp.
+ NET_C(U20.8, I_V12)
+ NET_C(U20.4, I_VM12)
+
+ CD4024_DIP(U21) // 7-Stage Ripple Binary Counter
+ NET_C(U21.7, GND)
+ NET_C(U21.14, I_V12)
+
+ CD4011_DIP(U22) // Quad 2-Input NAND Gates
+ NET_C(U22.7, GND)
+ NET_C(U22.14, I_V12)
+
+ CD4024_DIP(U23) // 7-Stage Ripple Binary Counter
+ NET_C(U23.7, GND)
+ NET_C(U23.14, I_V12)
+
+ TTL_7406_DIP(U24) // Hex inverter -- currently using a clone of 7416, no open collector behavior
+ NET_C(U24.7, GND)
+ NET_C(U24.14, I_V5)
+
+#if (!HLE_BACKGROUND_VCO)
+ LM566_DIP(U25) // Voltage-Controlled Oscillator
+#endif
+
+ TTL_74LS00_DIP(U26) // Quad 4-Input NAND Gate
+ NET_C(U26.7, GND)
+ NET_C(U26.14, I_V5)
+
+ TTL_7407_DIP(U27) // Hex Buffers with High Votage Open-Collector Outputs
+ NET_C(U27.7, GND)
+ NET_C(U27.14, I_V5)
+
+ TTL_7407_DIP(U28) // Hex Buffers with High Votage Open-Collector Outputs
+ NET_C(U28.7, GND)
+ NET_C(U28.14, I_V5)
+
+ TL081_DIP(U29) // Op. Amp.
+ NET_C(U29.7, I_V12)
+ NET_C(U29.4, I_VM12)
+
+// AY_3_8912_DIP(U30) // PSG -- emulated by MAME
+
+ CD4069_DIP(U31) // Hex Inverter
+ NET_C(U31.7, GND)
+ NET_C(U31.14, I_V12)
+
+ CD4069_DIP(U32) // Hex Inverter
+ NET_C(U32.7, GND)
+ NET_C(U32.14, I_V12)
+
+// TTL_74LS125_DIP(U33) // Quad 3-state buffer
+// NET_C(U33.7, GND)
+// NET_C(U33.14, I_V5)
+
+// TTL_74LS374_DIP(U34) // Octal D-Type Transparent Latches And Edge-Triggered Flip-Flop
+// NET_C(U34.10, GND)
+// NET_C(U34.20, I_V5)
+//
+// TTL_74LS374_DIP(U35) // Octal D-Type Transparent Latches And Edge-Triggered Flip-Flop
+// NET_C(U34.10, GND)
+// NET_C(U34.20, I_V5)
+
+// TTL_74LS74_DIP(U36) // Dual D Flip Flop
+// NET_C(U36.7, GND)
+// NET_C(U36.14, I_V5)
+
+// TTL_74LS10_DIP(U37) // Triple 3-Input NAND Gate
+// NET_C(U37.7, GND)
+// NET_C(U37.14, I_V5)
+
+// TTL_74LS14_DIP(U38)
+// NET_C(U38.7, GND)
+// NET_C(U38.14, I_V5)
+
+// TTL_74LS08_DIP(U39) // Quad 2-Input AND Gates
+// NET_C(U39.7, GND)
+// NET_C(U39.14, I_V5)
+
+// TTL_74LS30_DIP(U40) // 8-Input NAND Gate
+// NET_C(U40.7, GND)
+// NET_C(U40.14, I_V5)
+
+// TTL_74LS14_DIP(U41)
+// NET_C(U41.7, GND)
+// NET_C(U41.14, I_V5)
+
+ //
+ // Sheet 7, top-left/middle (Thrust)
+ //
+
+ NET_C(R58.1, GND)
+ NET_C(R58.2, U12.3, U10.6, U11.6, U15.6)
+ ALIAS(SUM_VCA, R58.2)
+ NET_C(U12.2, R75.1, R76.2)
+ NET_C(R76.1, GND)
+ NET_C(R75.2, U12.6)
+ ALIAS(BUFFER, U12.6)
+
+ NET_C(I_V12, U4.4, C75.2)
+ NET_C(C75.1, GND)
+ NET_C(U4.1, GND)
+ NET_C(U4.2, I_VM12, C76.2)
+ NET_C(C76.1, GND)
+ NET_C(U4.3, C77.1)
+ NET_C(C77.2, R27.2, U3.3)
+ NET_C(R27.1, GND)
+ NET_C(U3.2, U3.6, R28.1, R32.1)
+ ALIAS(WBN, U3.6)
+
+ NET_C(R28.2, C17.2, R29.1)
+ NET_C(C17.1, GND)
+ NET_C(R29.2, C18.2, R30.1)
+ NET_C(C18.1, GND)
+ NET_C(R30.2, R31.2, U10.2)
+ NET_C(R31.1, GND)
+ NET_C(U10.3, R56.2)
+ NET_C(R56.1, GND)
+
+ NET_C(I_THRUST_LOW, U24.5)
+ NET_C(U24.6, R99.1, R70.1)
+ NET_C(R99.2, I_V12)
+ NET_C(R70.2, R71.2, Q4.E)
+ NET_C(I_THRUST_HI, U24.3)
+ NET_C(U24.4, R100.1, R71.1)
+ NET_C(R100.2, I_V12)
+ NET_C(Q4.B, GND)
+ NET_C(Q4.C, R69.1)
+ NET_C(R69.2, U10.5)
+
+ NET_C(R32.2, C19.2, R33.1)
+ NET_C(C19.1, GND)
+ NET_C(R33.2, C20.2, R34.1)
+ NET_C(C20.1, GND)
+ NET_C(R34.2, R35.2, U11.2)
+ NET_C(R35.1, GND)
+ NET_C(U11.3, R57.2)
+ NET_C(R57.1, GND)
+
+ NET_C(I_THRUST_LSB, U24.1)
+ NET_C(U24.2, R77.1, R73.1)
+ NET_C(R77.2, I_V12)
+ NET_C(R73.2, R74.2, Q5.E)
+ NET_C(I_THRUST_MSB, U24.13)
+ NET_C(U24.12, R78.1, R74.1)
+ NET_C(R78.2, I_V12)
+ NET_C(Q5.B, GND)
+ NET_C(Q5.C, R72.1)
+ NET_C(R72.2, U11.5)
+
+ //
+ // Sheet 7, top-right (Skitter)
+ //
+
+ NET_C(I_SKITTER, U24.9)
+ NET_C(U24.8, R25.2, D1.K, R17.1)
+ NET_C(R17.2, I_V12)
+ NET_C(D1.A, C21.1, R26.2, R25.1, Q3.B)
+ NET_C(C21.2, GND)
+ NET_C(R26.1, GND)
+ NET_C(Q3.C, GND, Q2.C)
+ NET_C(Q3.E, R23.1)
+ NET_C(R23.2, R22.2)
+ NET_C(R22.1, Q2.E)
+
+#if (HLE_SKITTER_VCO)
+ //
+ // U1 is basically a standalone oscillator. Simulation at high
+ // frequency puts it at around 45Hz. Samples from real machines
+ // show it to be about 35Hz.
+ //
+ CLOCK(SKITTERCLK, 45)
+ NET_C(SKITTERCLK.GND, GND)
+ NET_C(SKITTERCLK.VCC, I_V12)
+ AFUNC(SKITTERENV, 1, "if(A0<6,2,18)")
+ NET_C(SKITTERENV.A0, SKITTERCLK.Q)
+ NET_C(SKITTERENV.Q, Q2.B)
+ NET_C(GND, C5.1, C5.2, C47.1, C47.2, R14.1, R14.2, R15.1, R15.2, R16.1, R16.2, R19.1, R19.2, U1.2, U1.3)
+#else
+ NET_C(Q2.B, R19.1)
+ NET_C(R19.2, C5.1)
+ NET_C(C5.2, C47.2, U1.2, R16.1)
+ NET_C(C47.1, GND)
+ NET_C(U1.3, R15.1, R14.2)
+ NET_C(R14.1, GND)
+ NET_C(R15.2, U1.6, R16.2)
+#endif
+
+ NET_C(C9.2, R21.1)
+ NET_C(C9.1, GND)
+ NET_C(R21.2, R18.1)
+ NET_C(R18.2, I_V12)
+ NET_C(I_V12, C8.1)
+ NET_C(C8.2, GND)
+ NET_C(U5.7, R18.1)
+ NET_C(U5.5, R23.2)
+ NET_C(U5.4, U24.8)
+ NET_C(U5.2, U5.6, R21.1)
+ NET_C(U5.8, I_V12)
+ NET_C(U5.1, GND)
+ NET_C(U5.3, R20.1)
+ NET_C(R20.2, C7.2, C6.1)
+ NET_C(C7.1, GND)
+ ALIAS(SKITTER, C6.2)
+
+ //
+ // Sheet 7, middle-right (Enemy Ship)
+ //
+
+ NET_C(I_ENEMY_SHIP, U24.11)
+ NET_C(U24.10, R60.1, U13.4)
+ NET_C(R60.2, I_V12)
+ NET_C(U13.7, R59.1, R61.2)
+ NET_C(R59.2, I_V12)
+ NET_C(R61.1, U13.2, U13.6, C30.2)
+ NET_C(C30.1, GND)
+ NET_C(U13.5, R145.1, R144.1)
+ ALIAS(_10HZ, R144.2)
+ NET_C(U13.1, GND)
+ NET_C(U13.8, I_V12, C29.2)
+ NET_C(C29.1, GND)
+ NET_C(U13.3, C28.1)
+ ALIAS(ENEMY_SHIP, C28.2)
+
+ ALIAS(_100HZ, R135.1)
+ NET_C(R145.2, R135.1)
+ ALIAS(_50HZ, R134.1)
+ ALIAS(_200HZA, R137.1)
+ ALIAS(_200HZB, R138.1)
+ NET_C(R138.2, R137.2, R134.2, R135.2, C61.2, R136.1)
+ NET_C(C61.1, GND)
+ NET_C(R136.2, Q11.E, U27.6)
+ NET_C(U27.5, U26.8)
+ NET_C(Q11.B, GND)
+ NET_C(Q11.C, R131.1)
+ NET_C(R131.2, U15.5)
+ NET_C(U15.2, R106.2, R83.2)
+ NET_C(R83.1, GND)
+ NET_C(U15.3, R82.2)
+ NET_C(R82.1, GND)
+
+ //
+ // Sheet 7, bottom-right (Background)
+ //
+
+ NET_C(I_BACKGROUND_LSB, U27.1, U26.10)
+ NET_C(U27.2, R107.1, R108.1)
+ NET_C(R107.2, I_V12)
+ NET_C(R108.2, R101.1, U16.6, R109.2)
+ NET_C(I_BACKGROUND_MSB, U27.3, U26.9)
+ NET_C(U27.4, R110.1, R109.1)
+ NET_C(R110.2, I_V12)
+ NET_C(U16.5, GND)
+ NET_C(U16.7, R101.2, R104.1)
+ NET_C(R104.2, U16.2, R105.1, C56.2)
+ NET_C(U16.3, R102.2, R103.1)
+ NET_C(R103.2, I_V12)
+ NET_C(R102.1, GND)
+ NET_C(U16.1, R105.2, C56.1, C60.1)
+ NET_C(C60.2, R130.1)
+ NET_C(R130.2, D8.K, C59.1)
+ NET_C(D8.A, I_V12)
+ NET_C(C59.2, GND)
+
+#if (HLE_BACKGROUND_VCO)
+ //
+ // R2 = 0.96310: HP = (0.000237231*A0) - 0.000561399
+ // R2 = 0.99617: HP = (0.0000527091*A0*A0) - (0.000501828*A0) + 0.00197538
+ // R2 = 0.99867: HP = (0.0000174335*A0*A0*A0) - (0.000309878*A0*A0) + (0.00198163*A0) - 0.00362162
+ // R2 = 0.99898: HP = (0.00000748879*A0*A0*A0*A0) - (0.000189174*A0*A0*A0) + (0.00180942*A0*A0) - (0.00759439*A0) + 0.0124560
+ // R2 = 0.99899: HP = (0.00000135301*A0*A0*A0*A0*A0) - (0.0000390321*A0*A0*A0*A0) + (0.000446417*A0*A0*A0) - (0.00250299*A0*A0) + (0.00693360*A0) - 0.00698302
+ //
+ VARCLOCK(BGCLK, 1, "max(0.000001,min(0.1,(0.00000748879*A0*A0*A0*A0) - (0.000189174*A0*A0*A0) + (0.00180942*A0*A0) - (0.00759439*A0) + 0.0124560))")
+ NET_C(BGCLK.GND, GND)
+ NET_C(BGCLK.VCC, I_V5)
+ NET_C(BGCLK.A0, U16.1)
+ NET_C(BGCLK.Q, BGENV.A0)
+ NET_C(GND, C57.1, C57.2, C58.1, C58.2)
+ AFUNC(BGENV, 1, "if(A0>2.5,2.5,-2.5)")
+ NET_C(BGENV.Q, R106.1)
+#else
+ NET_C(U16.1, U25.5)
+ NET_C(C60.2, U25.6)
+ NET_C(R130.2, U25.8)
+ NET_C(U25.7, C58.2)
+ NET_C(C58.1, GND)
+ NET_C(U25.1, GND)
+ NET_C(U25.3, C57.1)
+ NET_C(C57.2, R106.1)
+#endif
+
+ //
+ // Sheet 7, PSG input
+ //
+
+ NET_C(R_PSG_1.2, R_PSG_2.2, R_PSG_3.2, R133.2, C64.1)
+ NET_C(R133.1, GND)
+ NET_C(C64.2, R132.1)
+ NET_C(R132.2, U29.2, R122.1, C63.1)
+ NET_C(U29.3, GND)
+ NET_C(C63.2, R122.2, U29.6)
+ ALIAS(PSG, U29.6)
+
+ //
+ // Sheet 8, oscillators
+ //
+ // Pairs of CD4069 are used together with resistors and capacitors
+ // to create oscillators. The formula for the frequency is
+ // 1/(1.39*R*C). The following are simulated here:
+ //
+ // _200HZA: R142=330K, C68=0.01uF, Freq=218.01Hz
+ // _200HZB: R139=330K, C65=0.01uF, Freq=218.01Hz
+ // _10HZ: R143=680K, C69=0.1uF, Freq=10.58Hz
+ // _50HZ: R141=220K, C67=0.047uF, Freq=69.58Hz
+ // _100HZ: R140=270K, C66=0.022uF, Freq=121.12Hz
+ //
+
+ CLOCK(_200HZACLK, 218.01)
+ NET_C(_200HZACLK.VCC, I_V12)
+ NET_C(_200HZACLK.GND, GND)
+ NET_C(_200HZA, _200HZACLK.Q)
+ NET_C(R142.1, R142.2, C68.1, C68.2, U32.5, U32.9, GND)
+ HINT(U32.6, NC)
+ HINT(U32.8, NC)
+
+ CLOCK(_200HZBCLK, 217.98) // tweak frequency so this is out of phase
+ NET_C(_200HZBCLK.VCC, I_V12)
+ NET_C(_200HZBCLK.GND, GND)
+ NET_C(_200HZB, _200HZBCLK.Q)
+ NET_C(R139.1, R139.2, C65.1, C65.2, U32.13, U32.11, GND)
+ HINT(U32.12, NC)
+ HINT(U32.10, NC)
+
+ CLOCK(_10HZCLK, 10.58)
+ NET_C(_10HZCLK.VCC, I_V12)
+ NET_C(_10HZCLK.GND, GND)
+ NET_C(_10HZ, _10HZCLK.Q)
+ NET_C(R143.1, R143.2, C69.1, C69.2, U32.1, U32.3, GND)
+ HINT(U32.2, NC)
+ HINT(U32.4, NC)
+
+ CLOCK(_50HZCLK, 69.58)
+ NET_C(_50HZCLK.VCC, I_V12)
+ NET_C(_50HZCLK.GND, GND)
+ NET_C(_50HZ, _50HZCLK.Q)
+ NET_C(R141.1, R141.2, C67.1, C67.2, U31.1, U31.3, GND)
+ HINT(U31.2, NC)
+ HINT(U31.4, NC)
+
+ // Note this oscillator is on Sheet 7, in the right-middle section
+ CLOCK(_100HZCLK, 121.12)
+ NET_C(_100HZCLK.VCC, I_V12)
+ NET_C(_100HZCLK.GND, GND)
+ NET_C(_100HZ, _100HZCLK.Q)
+ NET_C(R140.1, R140.2, C66.1, C66.2, U31.5, U31.9, GND)
+ HINT(U31.6, NC)
+ HINT(U31.8, NC)
+
+ //
+ // Sheet 8, top middle (Explosion 1)
+ //
+
+ NET_C(WBN, R44.1)
+ NET_C(R44.2, C13.2, R45.1)
+ NET_C(C13.1, GND)
+ NET_C(R45.2, C14.2, R46.1)
+ NET_C(C14.1, GND)
+ NET_C(R46.2, R47.2, U8.2)
+ NET_C(R47.1, GND)
+ NET_C(U8.3, R54.2)
+ NET_C(R54.1, GND)
+ NET_C(U8.6, SUM_VCA)
+
+ NET_C(I_EXPLOSION_1, U28.11)
+ NET_C(U28.10, R120.1, U19.6)
+ NET_C(R120.2, I_V12)
+ NET_C(U19.5, R116.1, C51.1)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_EXPLOSION_1)
+ NET_C(D_EXPLOSION_1.A, U19.5)
+ NET_C(D_EXPLOSION_1.K, I_V12)
+#endif
+ NET_C(R116.2, I_V12)
+ NET_C(C51.2, U19.3)
+ NET_C(U19.4, U19.1, U19.2, R87.1)
+ NET_C(R87.2, Q9.E)
+ NET_C(Q9.B, GND)
+ NET_C(Q9.C, C37.1, R66.1)
+ NET_C(C37.2, I_VM12)
+ NET_C(R66.2, U8.5)
+
+ //
+ // Sheet 8, top right (Explosion 2)
+ //
+
+ NET_C(WBN, R48.1)
+ NET_C(R48.2, C15.2, R49.1)
+ NET_C(C15.1, GND)
+ NET_C(R49.2, C16.2, R50.1)
+ NET_C(C16.1, GND)
+ NET_C(R50.2, R51.2, U9.2)
+ NET_C(R51.1, GND)
+ NET_C(U9.3, R55.2)
+ NET_C(R55.1, GND)
+ NET_C(U9.6, SUM_VCA)
+
+ NET_C(I_EXPLOSION_2, U28.9)
+ NET_C(U28.8, R119.1, U19.8)
+ NET_C(R119.2, I_V12)
+ NET_C(U19.9, R117.1, C52.1)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_EXPLOSION_2)
+ NET_C(D_EXPLOSION_2.A, U19.9)
+ NET_C(D_EXPLOSION_2.K, I_V12)
+#endif
+ NET_C(R117.2, I_V12)
+ NET_C(C52.2, U19.11)
+ NET_C(U19.10, U19.12, U19.13, R88.1)
+ NET_C(R88.2, Q10.E)
+ NET_C(Q10.B, GND)
+ NET_C(Q10.C, C38.1, R68.1)
+ NET_C(C38.2, I_VM12)
+ NET_C(R68.2, U9.5)
+
+ //
+ // Sheet 8, bottom left (Explosion 3)
+
+ NET_C(WBN, R37.1)
+ NET_C(R37.2, C10.2, R38.1)
+ NET_C(C10.1, GND)
+ NET_C(R38.2, C11.2, R39.1)
+ NET_C(C11.1, GND)
+ NET_C(R39.2, R40.2, U6.2)
+ NET_C(R40.1, GND)
+ NET_C(U6.3, R52.2)
+ NET_C(R52.1, GND)
+ NET_C(U6.6, SUM_VCA)
+
+ NET_C(I_EXPLOSION_3, U28.5)
+ NET_C(U28.6, R118.1, U18.8)
+ NET_C(R118.2, I_V12)
+ NET_C(U18.9, R115.1, C50.1)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_EXPLOSION_3)
+ NET_C(D_EXPLOSION_3.A, U18.9)
+ NET_C(D_EXPLOSION_3.K, I_V12)
+#endif
+ NET_C(R115.2, I_V12)
+ NET_C(C50.2, U18.11)
+ NET_C(U18.10, U18.12, U18.13, R86.1)
+ NET_C(R86.2, Q8.E)
+ NET_C(Q8.B, GND)
+ NET_C(Q8.C, C36.1, R62.1)
+ NET_C(C36.2, I_VM12)
+ NET_C(R62.2, U6.5)
+
+ //
+ // Sheet 8, bottom left (Fireball)
+ //
+
+ NET_C(WBN, R41.1)
+ NET_C(R41.2, R43.2, U7.2, R42.2)
+ NET_C(R43.1, GND)
+ NET_C(R42.1, C12.2)
+ NET_C(C12.1, _50HZ)
+ NET_C(U7.3, R53.2)
+ NET_C(R53.1, GND)
+ NET_C(U7.6, SUM_VCA)
+
+ NET_C(I_FIREBALL, U28.13)
+ NET_C(U28.12, R111.1, U18.6)
+ NET_C(R111.2, I_V12)
+ NET_C(U18.5, R112.1, C49.1)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_FIREBALL)
+ NET_C(D_FIREBALL.A, U18.5)
+ NET_C(D_FIREBALL.K, I_V12)
+#endif
+ NET_C(R112.2, I_V12)
+ NET_C(C49.2, U18.3)
+ NET_C(U18.4, U18.1, U18.2, R85.1)
+ NET_C(R85.2, Q7.E)
+ NET_C(Q7.B, GND)
+ NET_C(Q7.C, R67.1)
+ NET_C(R67.2, C35.1, R64.1)
+ NET_C(C35.2, I_VM12)
+ NET_C(R64.2, U7.5)
+
+ //
+ // Sheet 8, bottom-ish middle (Bounce)
+ //
+
+ NET_C(_50HZ, C45.1)
+ NET_C(C45.2, R81.1)
+ NET_C(R81.2, R80.2, U14.2)
+#if (SOUND_VARIANT == VARIANT_ELIMINATOR)
+ NET_C(WBN, R79.1)
+ NET_C(R79.2, R80.2)
+#endif
+ NET_C(R80.1, GND)
+ NET_C(U14.3, R63.2)
+ NET_C(R63.1, GND)
+ NET_C(U14.6, SUM_VCA)
+
+ NET_C(I_BOUNCE, U28.3)
+ NET_C(U28.4, R114.1, U17.8)
+ NET_C(R114.2, I_V12)
+ NET_C(U17.9, R113.1, C48.1)
+ NET_C(R113.2, I_V12)
+ NET_C(C48.2, U17.11)
+ NET_C(U17.10, U17.13, U17.12, R84.1)
+ NET_C(R84.2, Q6.E)
+ NET_C(Q6.B, GND)
+ NET_C(Q6.C, C34.1, C33.1, R65.1)
+ NET_C(C33.2, C34.2, I_VM12)
+ NET_C(R65.2, U14.5)
+
+ //
+ // Sheet 8, bottom middle (Torpedo 1)
+ //
+
+ NET_C(I_TORPEDO_1, U27.9)
+ NET_C(U27.8, R125.1, U22.8)
+ NET_C(R125.2, I_V12)
+ NET_C(U22.9, R124.1, C55.1)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_TORPEDO_1)
+ NET_C(D_TORPEDO_1.A, U22.9)
+ NET_C(D_TORPEDO_1.K, I_V12)
+#endif
+ NET_C(R124.2, I_V12)
+ NET_C(C55.2, U22.11, U23.2)
+ NET_C(U22.10, U22.12, U22.13, D4.K)
+ NET_C(D4.A, R89.1)
+ NET_C(R89.2, C39.2, D2.K)
+ NET_C(C39.1, GND)
+
+#if (HLE_TORPEDO1_VCO)
+ //
+ // R2 = 0.99044: HP = (0.000104804*A0) - 0.00000213808
+ // R2 = 0.99913: HP = (0.0000155103*A0*A0) + (0.0000595259*A0) + 0.0000223086
+ // R2 = 0.99930: HP = (0.00000342725*A0*A0*A0) + (0.000000183693*A0*A0) + (0.000079091*A0) + 0.0000157375
+ // R2 = 0.99930: HP = (-0.000000204983*A0*A0*A0*A0) + (0.00000466123*A0*A0*A0) - (0.00000232484*A0*A0) + (0.000081060*A0) + 0.0000152562
+ // R2 = 0.99931: HP = (-0.00000210641*A0*A0*A0*A0*A0) + (0.0000157326*A0*A0*A0*A0) - (0.0000399041*A0*A0*A0) + (0.0000541020*A0*A0) + (0.0000495068*A0) + 0.0000213321
+ //
+ VARCLOCK(TORP1CLK, 1, "max(0.000001,min(0.1,(0.00000342725*A0*A0*A0) + (0.000000183693*A0*A0) + (0.000079091*A0) + 0.0000157375))")
+ NET_C(TORP1CLK.GND, GND)
+ NET_C(TORP1CLK.VCC, I_V5)
+ NET_C(TORP1CLK.A0, D2.K)
+ NET_C(TORP1CLK.Q, T1ENV.A0)
+ AFUNC(T1ENV, 1, "if(A0>2.5,11.1,-11.1)")
+ NET_C(T1ENV.Q, U23.1)
+ NET_C(D2.A, D3.K, R91.1)
+ NET_C(C46.2, R90.1)
+ NET_C(R90.2, R91.2, R146.1)
+ NET_C(GND, U20.3, U20.2)
+#else
+ NET_C(D2.A, D3.K, R91.1, U20.3)
+ NET_C(U20.2, C46.2, R90.1)
+ NET_C(R90.2, U20.1, R91.2, R146.1)
+#endif
+ NET_C(D3.A, GND)
+ NET_C(C46.1, GND)
+ NET_C(R146.2, U23.1)
+
+ NET_C(U23.12, R129.1)
+ NET_C(U23.11, R128.1)
+ NET_C(U23.9, R126.1)
+ NET_C(U23.6, R127.1)
+ NET_C(R127.2, R126.2, R128.2, R129.2, C44.1)
+
+ //
+ // Sheet 8, middle (Torpedo 2)
+ //
+
+ NET_C(WBN, R36.1)
+#if (DISABLE_TORPEDO2_NOISE)
+ NET_C(R36.2, GND) // noise source
+#else
+ NET_C(R36.2, D6.A) // noise source
+#endif
+
+#if (HLE_TORPEDO2_VCO)
+ //
+ // R2 = 0.98868: HP = (0.000142472*A0) - 0.0000121481
+ // R2 = 0.99851: HP = (0.0000304790*A0*A0) + (0.000072730*A0) + 0.0000185913
+ // R2 = 0.99875: HP = (0.0000104419*A0*A0*A0) - (0.00000603211*A0*A0) + (0.000109865*A0) + 0.0000082421
+ // R2 = 0.99875: HP = (0.000000506238*A0*A0*A0*A0) + (0.0000080617*A0*A0*A0) - (0.00000220640*A0*A0) + (0.000107441*A0) + 0.0000087378
+ // R2 = 0.99876: HP = (-0.0000095532*A0*A0*A0*A0*A0) + (0.0000569271*A0*A0*A0*A0) - (0.000116200*A0*A0*A0) + (0.000123414*A0*A0) + (0.0000501789*A0) + 0.0000180007
+ //
+ VARCLOCK(TORP2CLK, 1, "max(0.000001,min(0.1,(0.0000104419*A0*A0*A0) - (0.00000603211*A0*A0) + (0.000109865*A0) + 0.0000082421))")
+ NET_C(TORP2CLK.GND, GND)
+ NET_C(TORP2CLK.VCC, I_V5)
+ NET_C(TORP2CLK.A0, D6.K)
+ NET_C(TORP2CLK.Q, T2ENV.A0)
+ AFUNC(T2ENV, 1, "if(A0>2.5,11.1,-11.1)")
+ NET_C(T2ENV.Q, U21.1)
+ NET_C(D6.A, D7.K, R93.1)
+ NET_C(C43.2, R94.1)
+ NET_C(R94.2, R93.2, R92.2)
+ NET_C(GND, U20.6, U20.5)
+#else
+ NET_C(D6.A, U20.5, D7.K, R93.1)
+ NET_C(U20.6, C43.2, R94.1)
+ NET_C(R94.2, U20.7, R93.2, R92.2)
+#endif
+
+ NET_C(D7.A, GND)
+ NET_C(D6.K, C53.2, R147.2)
+ NET_C(C53.1, GND)
+ NET_C(R147.1, D5.A)
+ NET_C(U22.4, U22.1, U22.2, D5.K)
+ NET_C(C43.1, GND)
+ NET_C(R92.1, U21.1)
+
+ NET_C(I_TORPEDO_2, U27.11)
+ NET_C(U27.10, R123.1, U22.6)
+ NET_C(R123.2, I_V12)
+ NET_C(U22.5, R121.1, C54.1)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_TORPEDO_2)
+ NET_C(D_TORPEDO_2.A, U22.5)
+ NET_C(D_TORPEDO_2.K, I_V12)
+#endif
+ NET_C(R121.2, I_V12)
+ NET_C(C54.2, U22.3, U21.2)
+ NET_C(U21.12, R98.1)
+ NET_C(U21.11, R97.1)
+ NET_C(U21.9, R95.1)
+ NET_C(U21.6, R96.1)
+ NET_C(R98.2, R97.2, R95.2, R96.2, C44.1)
+
+ //
+ // Sheet 8, middle right (Final sum)
+ //
+
+ NET_C(PSG, R10.1)
+ NET_C(ENEMY_SHIP, R7.1)
+ NET_C(SKITTER, R6.1)
+ NET_C(BUFFER, R8.1)
+ NET_C(C44.2, R9.1)
+ NET_C(R10.2, R7.2, R6.2, R8.2, R9.2)
+ ALIAS(OUTPUT, R9.2)
+
+ //
+ // Unconnected inputs
+ //
+
+ NET_C(GND, U17.1, U17.2, U17.5, U17.6)
+ NET_C(GND, U26.1, U26.2, U26.4, U26.5, U26.12, U26.13)
+ NET_C(GND, U27.13, U28.1)
+ NET_C(GND, U31.11, U31.13)
+
+ //
+ // Unconnected outputs
+ //
+
+
+#if (ENABLE_FRONTIERS)
+#define RXX 384
+ OPTIMIZE_FRONTIER(R10.1, RES_K(10), RXX)
+ OPTIMIZE_FRONTIER(R7.1, RES_K(220), RXX)
+ OPTIMIZE_FRONTIER(R6.1, RES_K(220), RXX)
+ OPTIMIZE_FRONTIER(R8.1, RES_K(10), RXX)
+#endif
+
+NETLIST_END()
+
+#endif
diff --git a/src/mame/audio/nl_elim.h b/src/mame/audio/nl_elim.h
new file mode 100644
index 00000000000..a9cd5a2ea4b
--- /dev/null
+++ b/src/mame/audio/nl_elim.h
@@ -0,0 +1,11 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+#ifndef MAME_AUDIO_NL_ELIM_H
+#define MAME_AUDIO_NL_ELIM_H
+
+#pragma once
+
+NETLIST_EXTERNAL(elim)
+NETLIST_EXTERNAL(zektor)
+
+#endif // MAME_AUDIO_NL_ELIM_H
diff --git a/src/mame/audio/nl_segaspeech.cpp b/src/mame/audio/nl_segaspeech.cpp
new file mode 100644
index 00000000000..6b52f886df5
--- /dev/null
+++ b/src/mame/audio/nl_segaspeech.cpp
@@ -0,0 +1,119 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+
+//
+// Netlist for Sega Speech board
+//
+// Derived from the schematics in the Sega G-80 manual.
+//
+// Known problems/issues:
+//
+// * Mostly works. Not 100% sure about using a current source
+// for input.
+//
+
+#include "netlist/devices/net_lib.h"
+#include "nl_segaspeech.h"
+
+//
+// Optimizations
+//
+
+
+
+
+//
+// Main netlist
+//
+
+NETLIST_START(segaspeech)
+
+ SOLVER(Solver, 1000)
+ PARAM(Solver.DYNAMIC_TS, 1)
+ PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 2e-5)
+
+ TTL_INPUT(I_SP0250, 0)
+ PARAM(I_SP0250.MODEL, "74XXOC")
+ NET_C(I_SP0250.GND, GND)
+ NET_C(I_SP0250.VCC, I_V5)
+ ALIAS(I_SPEECH, I_SP0250.Q)
+
+ ANALOG_INPUT(I_V5, 5)
+ ANALOG_INPUT(I_VM5, -5)
+
+ //
+ // There are two schematic drawings of the speech board
+ // that show fairly different outputs from the SP0250.
+ // Both have their problems.
+ //
+ // The simpler one is included in the Astro Blaster and
+ // Space Fury manuals. This is largely correct, except
+ // that it is believed (not verified) that R20 should be
+ // 4.7K instead of 470 Ohms. This schematic does not show
+ // the CD4053 mixer.
+ //
+ // The more complex schematic is included in the G-80
+ // schematics package, and in the Star Trek and Zektor
+ // manuals. It has several significant errors (all verified
+ // from a working PCB):
+ //
+ // 1. U8 pins 2 and 3 are swapped
+ // 2. The connection from R20 to GND should be removed
+ // (this also disconnected C50 and R21 from GND)
+ // 3. R13 should be 220k, not 22k
+ //
+ // With the fixes above, the output sections of the two
+ // schematics line up, minus the mixing section, which is
+ // only shown on the more complex schematic.
+ //
+ // The mixing section is trivial, with 3 bits from a control
+ // port controlling three switches in the CD4053. Bit 3
+ // enables/disables speech. Bit 4 enables/disables an
+ // unconnected source. And bit 5 enables/disables incoming
+ // external sound. The incoming sound is also routed through
+ // a pot to enable control over the relative volume.
+ //
+ // For purposes of this netlist, and since it runs at high
+ // speeds, we tap the speech output before it hits the
+ // CD4053 and manually manage the speech output.
+ //
+ // Since we use MAME to manage the mixing, the control bits
+ // are managed directly there, rather than in this netlist.
+ //
+
+ //
+ // This represents the schematic drawing from Astro Blaster
+ // and Space Fury; there is no control register and it
+ // works.
+ //
+ RES(R17, RES_K(10))
+ RES(R18, RES_K(22))
+ RES(R19, RES_K(250))
+ RES(R20, RES_K(4.7)) // schematic shows 470Ohm, but a real PCB had 4.7k here
+ RES(R21, RES_K(10))
+
+ CAP(C9, CAP_U(0.1))
+ CAP(C10, CAP_U(0.047))
+ CAP(C50, CAP_U(0.003))
+
+ TL081_DIP(U8) // Op. Amp.
+ NET_C(U8.7, I_V5)
+ NET_C(U8.4, I_VM5)
+
+ NET_C(I_SPEECH, R17.1, C9.1)
+ NET_C(R17.2, I_V5)
+ NET_C(C9.2, R18.1)
+ NET_C(R18.2, C10.1, R19.2, U8.3)
+ NET_C(R19.1, C10.2, GND)
+ NET_C(R20.1, GND)
+ NET_C(R20.2, U8.2, R21.2, C50.2)
+ NET_C(U8.6, R21.1, C50.1)
+ ALIAS(OUTPUT, U8.6)
+
+ //
+ // In the more complex case, this would feed into a
+ // CD4053 for switching. We rely on this being managed
+ // at the driver level.
+ //
+
+NETLIST_END()
diff --git a/src/mame/audio/nl_segaspeech.h b/src/mame/audio/nl_segaspeech.h
new file mode 100644
index 00000000000..e9779772eba
--- /dev/null
+++ b/src/mame/audio/nl_segaspeech.h
@@ -0,0 +1,10 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+#ifndef MAME_AUDIO_NL_SEGASPEECH_H
+#define MAME_AUDIO_NL_SEGASPEECH_H
+
+#pragma once
+
+NETLIST_EXTERNAL(segaspeech)
+
+#endif // MAME_AUDIO_NL_SEGASPEECH_H
diff --git a/src/mame/audio/nl_segausb.cpp b/src/mame/audio/nl_segausb.cpp
new file mode 100644
index 00000000000..179f9b4a211
--- /dev/null
+++ b/src/mame/audio/nl_segausb.cpp
@@ -0,0 +1,544 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+
+//
+// Netlist for Sega Universal Sound Board
+//
+// The Sega Universal Sound Board was used by several early G80
+// vector and raster games, notably Star Trek and Tac/Scan,
+// among others. It is largely implemented as a MAME device, but
+// the analog audio section is implemented here.
+//
+// Known problems/issues:
+//
+// * WIP.
+//
+
+#include "netlist/devices/net_lib.h"
+#include "nl_segausb.h"
+
+
+
+//
+// Optimizations
+//
+
+#define USE_AFUNC_MIXING (1)
+#define ENABLE_NOISE_FRONTIERS (1)
+#define UNDERCLOCK_NOISE_GEN (1)
+#define ENABLE_FRONTIERS (0)
+
+
+
+//
+// Hacks
+//
+
+
+
+NETLIST_START(segausb)
+
+ SOLVER(Solver, 1000)
+ PARAM(Solver.DYNAMIC_TS, 1)
+ PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 2e-5)
+
+ ANALOG_INPUT(I_U12_DAC, 0) // AD7524
+ ANALOG_INPUT(I_U13_DAC, 0) // AD7524
+ ANALOG_INPUT(I_U14_DAC, 0) // AD7524
+ TTL_INPUT(I_U2B_SEL, 0) // 74LS74
+
+ ANALOG_INPUT(I_U24_DAC, 0) // AD7524
+ ANALOG_INPUT(I_U25_DAC, 0) // AD7524
+ ANALOG_INPUT(I_U26_DAC, 0) // AD7524
+ TTL_INPUT(I_U38B_SEL, 0) // 74LS74
+
+ ANALOG_INPUT(I_U27_DAC, 0) // AD7524
+ ANALOG_INPUT(I_U28_DAC, 0) // AD7524
+ ANALOG_INPUT(I_U29_DAC, 0) // AD7524
+ TTL_INPUT(I_U2A_SEL, 0) // 74LS74
+
+ NET_C(GND, I_U2B_SEL.GND, I_U38B_SEL.GND, I_U2A_SEL.GND)
+ NET_C(I_V5, I_U2B_SEL.VCC, I_U38B_SEL.VCC, I_U2A_SEL.VCC)
+
+ TTL_INPUT(I_U41_OUT0, 0) // 8253 PIT U41
+ TTL_INPUT(I_U41_OUT1, 0)
+ TTL_INPUT(I_U41_OUT2, 0)
+
+ TTL_INPUT(I_U42_OUT0, 0) // 8253 PIT U42
+ TTL_INPUT(I_U42_OUT1, 0)
+ TTL_INPUT(I_U42_OUT2, 0)
+
+ TTL_INPUT(I_U43_OUT0, 0) // 8253 PIT U43
+ TTL_INPUT(I_U43_OUT1, 0)
+ TTL_INPUT(I_U43_OUT2, 0)
+
+ NET_C(GND, I_U41_OUT0.GND, I_U41_OUT1.GND, I_U41_OUT2.GND)
+ NET_C(I_V5, I_U41_OUT0.VCC, I_U41_OUT1.VCC, I_U41_OUT2.VCC)
+
+ NET_C(GND, I_U42_OUT0.GND, I_U42_OUT1.GND, I_U42_OUT2.GND)
+ NET_C(I_V5, I_U42_OUT0.VCC, I_U42_OUT1.VCC, I_U42_OUT2.VCC)
+
+ NET_C(GND, I_U43_OUT0.GND, I_U43_OUT1.GND, I_U43_OUT2.GND)
+ NET_C(I_V5, I_U43_OUT0.VCC, I_U43_OUT1.VCC, I_U43_OUT2.VCC)
+
+ ANALOG_INPUT(I_V5, 5)
+ ANALOG_INPUT(I_V12, 12)
+ ANALOG_INPUT(I_VM12, -12)
+
+ RES(R7, RES_K(100))
+ RES(R8, RES_K(100))
+ RES(R9, RES_K(100))
+ RES(R10, RES_K(100))
+ RES(R12, RES_K(100))
+ RES(R13, RES_K(100))
+ RES(R14, RES_K(33))
+ RES(R15, RES_K(100))
+ RES(R16, RES_K(100))
+ RES(R17, RES_K(5.6))
+ RES(R18, RES_K(100))
+ RES(R19, RES_K(100))
+ RES(R20, RES_K(10))
+ RES(R21, RES_K(10))
+ RES(R22, RES_K(10))
+ RES(R23, RES_K(1))
+ RES(R24, RES_K(1))
+ RES(R25, RES_K(100))
+ RES(R26, RES_K(5.6))
+ RES(R27, RES_K(10))
+ RES(R28, RES_K(100))
+ RES(R29, RES_K(100))
+ RES(R30, RES_K(1))
+ RES(R31, RES_K(100))
+ RES(R32, RES_K(100))
+ RES(R33, RES_K(1))
+ RES(R34, RES_K(100))
+ RES(R35, RES_K(100))
+ RES(R36, RES_K(100))
+ RES(R37, RES_K(33))
+ RES(R38, RES_K(100))
+ RES(R39, RES_K(100))
+ RES(R40, RES_K(10))
+ RES(R41, RES_K(10))
+ RES(R42, RES_K(100))
+ RES(R43, RES_K(100))
+ RES(R44, RES_K(33))
+ RES(R45, RES_K(100))
+ RES(R46, RES_K(100))
+ RES(R47, RES_K(5.6))
+ RES(R48, RES_K(100))
+ RES(R49, RES_K(100))
+ RES(R50, RES_K(10))
+ RES(R51, RES_K(10))
+ RES(R52, RES_K(10))
+ RES(R53, RES_K(1))
+ RES(R54, RES_K(100))
+ RES(R55, RES_K(100))
+ RES(R56, RES_K(1))
+ RES(R59, RES_K(1))
+ RES(R60, RES_K(2.2))
+ RES(R61, RES_K(33))
+ RES(R62, 270)
+ RES(R63, RES_K(1))
+ RES(R64, RES_K(2.7))
+ RES(R65, RES_K(2.7))
+
+// CAP(C6, CAP_P(100))
+// CAP(C7, CAP_P(100))
+// CAP(C8, CAP_P(100))
+ CAP(C9, CAP_U(0.01))
+ CAP(C13, CAP_U(0.01))
+ CAP(C14, CAP_U(1))
+ CAP(C15, CAP_U(1))
+ CAP(C16, CAP_U(0.01))
+ CAP(C17, CAP_U(0.01))
+// CAP(C19, CAP_P(100))
+// CAP(C20, CAP_P(100))
+// CAP(C21, CAP_P(100))
+// CAP(C22, CAP_P(100))
+// CAP(C23, CAP_P(100))
+// CAP(C24, CAP_P(100))
+ CAP(C25, CAP_U(0.01))
+ CAP(C32, CAP_U(0.01))
+ CAP(C33, CAP_U(1))
+ CAP(C34, CAP_U(1))
+ CAP(C35, CAP_U(1))
+ CAP(C36, CAP_U(1))
+ CAP(C51, CAP_U(0.15))
+ CAP(C52, CAP_U(0.1))
+ CAP(C53, CAP_U(0.082))
+ CAP(C54, CAP_U(1))
+ CAP(C55, CAP_U(0.15))
+ CAP(C56, CAP_U(0.15))
+
+// TL082_DIP(U1) // Op. Amp.
+// NET_C(U1.7, I_V12)
+// NET_C(U1.4, I_VM12)
+
+// TTL_74LS74(U2) // Dual D-Type Positive Edge-Triggered Flip-Flop -- not emulated
+// NET_C(U2.7, GND)
+// NET_C(U2.14, I_V5)
+
+ TL082_DIP(U3) // Op. Amp.
+ NET_C(U3.8, I_V12)
+ NET_C(U3.4, I_VM12)
+
+ TL082_DIP(U4) // Op. Amp.
+ NET_C(U4.8, I_V12)
+ NET_C(U4.4, I_VM12)
+
+ TL082_DIP(U5) // Op. Amp.
+ NET_C(U5.8, I_V12)
+ NET_C(U5.4, I_VM12)
+
+ TL082_DIP(U6) // Op. Amp.
+ NET_C(U6.8, I_V12)
+ NET_C(U6.4, I_VM12)
+
+ CD4053_DIP(U7) // 3x analog demuxer
+ NET_C(U7.16, I_V5)
+ NET_C(U7.6, GND) // INH
+ NET_C(U7.7, I_V12) // VEE
+ NET_C(U7.8, GND)
+
+ CD4053_DIP(U8) // 3x analog demuxer
+ NET_C(U8.16, I_V5)
+ NET_C(U8.6, GND) // INH
+ NET_C(U8.7, I_V12) // VEE
+ NET_C(U8.8, GND)
+
+ TL082_DIP(U9) // Op. Amp.
+ NET_C(U9.8, I_V12)
+ NET_C(U9.4, I_VM12)
+
+// TTL_74LS139_DIP(U10) // Dual 1-of-4 Decoder -- not emulated
+
+// TTL_74LS139_DIP(U11) // Dual 1-of-4 Decoder -- not emulated
+
+// AD7524_DIP(U12) // DAC -- not emulated
+// NET_C(U12.3, GND)
+// NET_C(U12.14, I_V5)
+
+// AD7524_DIP(U13) // DAC -- not emulated
+// NET_C(U12.3, GND)
+// NET_C(U12.14, I_V5)
+
+// AD7524_DIP(U14) // DAC -- not emulated
+// NET_C(U12.3, GND)
+// NET_C(U12.14, I_V5)
+
+ CD4053_DIP(U15) // 3x analog demuxer
+ NET_C(U15.16, I_V5)
+ NET_C(U15.6, GND) // INH
+ NET_C(U15.7, I_V12) // VEE
+ NET_C(U15.8, GND)
+
+ CD4053_DIP(U16) // 3x analog demuxer
+ NET_C(U16.16, I_V5)
+ NET_C(U16.6, GND) // INH
+ NET_C(U16.7, I_V12) // VEE
+ NET_C(U16.8, GND)
+
+ TL082_DIP(U17) // Op. Amp.
+ NET_C(U17.8, I_V12)
+ NET_C(U17.4, I_VM12)
+
+ TL082_DIP(U18) // Op. Amp.
+ NET_C(U18.8, I_V12)
+ NET_C(U18.4, I_VM12)
+
+ TL082_DIP(U19) // Op. Amp.
+ NET_C(U19.8, I_V12)
+ NET_C(U19.4, I_VM12)
+
+ TL082_DIP(U20) // Op. Amp.
+ NET_C(U20.8, I_V12)
+ NET_C(U20.4, I_VM12)
+
+ TL082_DIP(U21) // Op. Amp.
+ NET_C(U21.8, I_V12)
+ NET_C(U21.4, I_VM12)
+
+ TL082_DIP(U22) // Op. Amp.
+ NET_C(U22.8, I_V12)
+ NET_C(U22.4, I_VM12)
+
+ TL082_DIP(U23) // Op. Amp.
+ NET_C(U23.8, I_V12)
+ NET_C(U23.4, I_VM12)
+
+// AD7524_DIP(U24) // DAC -- not emulated
+// NET_C(U24.3, GND)
+// NET_C(U24.14, I_V5)
+
+// AD7524_DIP(U25) // DAC -- not emulated
+// NET_C(U25.3, GND)
+// NET_C(U25.14, I_V5)
+
+// AD7524_DIP(U26) // DAC -- not emulated
+// NET_C(U26.3, GND)
+// NET_C(U26.14, I_V5)
+
+// AD7524_DIP(U27) // DAC -- not emulated
+// NET_C(U27.3, GND)
+// NET_C(U27.14, I_V5)
+
+// AD7524_DIP(U28) // DAC -- not emulated
+// NET_C(U28.3, GND)
+// NET_C(U28.14, I_V5)
+
+// AD7524_DIP(U29) // DAC -- not emulated
+// NET_C(U29.3, GND)
+// NET_C(U29.14, I_V5)
+
+ CD4053_DIP(U30) // 3x analog demuxer
+ NET_C(U30.16, I_V5)
+ NET_C(U30.6, GND) // INH
+ NET_C(U30.7, I_V12) // VEE
+ NET_C(U30.8, GND)
+
+ CD4053_DIP(U31) // 3x analog demuxer
+ NET_C(U31.16, I_V5)
+ NET_C(U31.6, GND) // INH
+ NET_C(U31.7, I_V12) // VEE
+ NET_C(U31.8, GND)
+
+// TTL_74LS74(U38) // Dual D-Type Positive Edge-Triggered Flip-Flop -- not emulated
+// NET_C(U38.7, GND)
+// NET_C(U38.14, I_V5)
+
+ TL081_DIP(U49) // Op. Amp.
+ NET_C(U49.7, I_V12)
+ NET_C(U49.4, I_VM12)
+
+ MM5837_DIP(U60)
+ NET_C(U60.2, I_VM12)
+ NET_C(U60.4, I_V12)
+#if (UNDERCLOCK_NOISE_GEN)
+ // officially runs at 48-112kHz, but little noticeable difference
+ // in exchange for a big performance boost
+ PARAM(U60.FREQ, 24000)
+#endif
+
+ //
+ // Sheet 6, noise source
+ //
+
+ NET_C(U60.1, GND)
+ NET_C(U60.3, R65.1)
+ NET_C(R65.2, R64.2, R63.2, R62.2, C53.2, C52.1)
+ NET_C(R64.1, C54.1)
+ NET_C(C54.2, GND)
+ NET_C(R63.1, C55.2, C56.2)
+ NET_C(C55.1, GND)
+ NET_C(C56.1, GND)
+ NET_C(R62.1, C51.2)
+ NET_C(C51.1, GND)
+ NET_C(C53.1, GND)
+ NET_C(C52.2, R61.2, U49.3)
+ NET_C(R61.1, GND)
+ NET_C(U49.2, R60.1, R59.2)
+ NET_C(R60.2, U49.6)
+ NET_C(R59.1, GND)
+#if (ENABLE_NOISE_FRONTIERS)
+ AFUNC(NOISEFUNC, 1, "A0")
+ NET_C(R60.2, NOISEFUNC.A0)
+ ALIAS(NOISE, NOISEFUNC.Q)
+#else
+ ALIAS(NOISE, R60.2)
+#endif
+
+ //
+ // Sheet 7, top-left
+ //
+
+ NET_C(I_U42_OUT0, C14.1)
+ NET_C(C14.2, R20.2, U3.5)
+ NET_C(R20.1, GND)
+ NET_C(U3.6, U3.7)
+ AFUNC(DAC_U12, 2, "A0*A1")
+ NET_C(DAC_U12.A0, U3.7)
+ NET_C(DAC_U12.A1, I_U12_DAC)
+ NET_C(DAC_U12.Q, R12.2)
+
+ NET_C(I_U42_OUT1, C15.1)
+ NET_C(C15.2, R21.2, U4.5)
+ NET_C(R21.1, GND)
+ NET_C(U4.6, U4.7)
+ AFUNC(DAC_U13, 2, "A0*A1")
+ NET_C(DAC_U13.A0, U4.7)
+ NET_C(DAC_U13.A1, I_U13_DAC)
+ NET_C(DAC_U13.Q, R13.2)
+
+ NET_C(I_U42_OUT2, U15.10, U15.9)
+ NET_C(U15.15, U15.14, R32.1)
+ NET_C(U15.1, R33.1)
+ NET_C(U15.12, NOISE)
+ NET_C(U15.13, U16.3)
+ NET_C(U15.11, U16.11, U16.10, U16.9, I_U2B_SEL)
+ NET_C(R33.2, C13.2, R32.2, R31.1, U15.4)
+ NET_C(C13.1, GND)
+ NET_C(U15.3, R30.1)
+ NET_C(R31.2, R30.2, C9.2, U6.3)
+ NET_C(C9.1, GND)
+ NET_C(U6.2, R22.2, R17.1)
+ NET_C(R22.1, GND)
+ NET_C(R17.2, U6.1, U16.14)
+
+ NET_C(U16.13, U16.5, R9.1)
+ NET_C(U16.12, R19.2)
+ NET_C(U16.15, NOISE)
+ NET_C(U16.1, R18.2)
+ NET_C(R18.1, R19.1, U5.6, R15.2)
+ NET_C(U5.5, GND)
+ NET_C(R15.1, U5.7)
+ AFUNC(DAC_U14, 2, "A0*A1")
+ PARAM(DAC_U14.THRESH, 1e-5)
+ NET_C(DAC_U14.A0, U5.7)
+ NET_C(DAC_U14.A1, I_U14_DAC)
+ NET_C(DAC_U14.Q, R14.2)
+ NET_C(R14.1, R13.1, R12.1, U6.6, R16.1)
+ NET_C(U6.5, GND)
+ NET_C(U6.7, R16.2, U16.4)
+
+ //
+ // Sheet 7, bottom-left
+ //
+
+ NET_C(I_U41_OUT0, C34.1)
+ NET_C(C34.2, R41.2, U19.5)
+ NET_C(R41.1, GND)
+ NET_C(U19.6, U19.7)
+ AFUNC(DAC_U26, 2, "A0*A1")
+ NET_C(DAC_U26.A0, U19.7)
+ NET_C(DAC_U26.A1, I_U26_DAC)
+ NET_C(DAC_U26.Q, R39.2)
+
+ NET_C(I_U41_OUT1, C33.1)
+ NET_C(C33.2, R40.2, U18.5)
+ NET_C(R40.1, GND)
+ NET_C(U18.6, U18.7)
+ AFUNC(DAC_U25, 2, "A0*A1")
+ NET_C(DAC_U25.A0, U18.7)
+ NET_C(DAC_U25.A1, I_U25_DAC)
+ NET_C(DAC_U25.Q, R38.2)
+
+ NET_C(I_U41_OUT2, U8.10, U8.9)
+ NET_C(U8.15, U8.14, R25.1)
+ NET_C(U8.1, R24.1)
+ NET_C(U8.12, NOISE)
+ NET_C(U8.13, U7.3)
+ NET_C(U8.11, U7.11, U7.10, U7.9, I_U38B_SEL)
+ NET_C(R24.2, C16.2, R25.2, R29.1, U8.4)
+ NET_C(C16.1, GND)
+ NET_C(U8.3, R23.1)
+ NET_C(R23.2, R29.2, C17.2, U9.3)
+ NET_C(C17.1, GND)
+ NET_C(U9.2, R27.2, R26.1)
+ NET_C(R27.1, GND)
+ NET_C(R26.2, U9.1, U7.14)
+
+ NET_C(U7.13, U7.5, R8.1)
+ NET_C(U7.12, R35.2)
+ NET_C(U7.15, NOISE)
+ NET_C(U7.1, R34.2)
+ NET_C(R34.1, R35.1, U17.6, R36.2)
+ NET_C(U17.5, GND)
+ NET_C(R36.1, U17.7)
+ AFUNC(DAC_U24, 2, "A0*A1")
+ PARAM(DAC_U24.THRESH, 1e-5)
+ NET_C(DAC_U24.A0, U17.7)
+ NET_C(DAC_U24.A1, I_U24_DAC)
+ NET_C(DAC_U24.Q, R37.2)
+ NET_C(R37.1, R38.1, R39.1, U9.6, R28.1)
+ NET_C(U9.5, GND)
+ NET_C(U9.7, R28.2, U7.4)
+
+ //
+ // Sheet 7, top-right
+ //
+
+ NET_C(I_U43_OUT0, C35.1)
+ NET_C(C35.2, R50.2, U20.5)
+ NET_C(R50.1, GND)
+ NET_C(U20.6, U20.7)
+ AFUNC(DAC_U27, 2, "A0*A1")
+ NET_C(DAC_U27.A0, U20.7)
+ NET_C(DAC_U27.A1, I_U27_DAC)
+ NET_C(DAC_U27.Q, R42.2)
+
+ NET_C(I_U43_OUT1, C36.1)
+ NET_C(C36.2, R51.2, U21.5)
+ NET_C(R51.1, GND)
+ NET_C(U21.6, U21.7)
+ AFUNC(DAC_U28, 2, "A0*A1")
+ NET_C(DAC_U28.A0, U21.7)
+ NET_C(DAC_U28.A1, I_U28_DAC)
+ NET_C(DAC_U28.Q, R43.2)
+
+ NET_C(I_U43_OUT2, U30.10, U30.9)
+ NET_C(U30.15, U30.14, R55.1)
+ NET_C(U30.1, R56.1)
+ NET_C(U30.12, NOISE)
+ NET_C(U30.13, U31.3)
+ NET_C(U30.11, U31.11, U31.10, U31.9, I_U2A_SEL)
+ NET_C(R54.2, C32.2, R55.2, R56.2, U30.4)
+ NET_C(C32.1, GND)
+ NET_C(U30.3, R53.1)
+ NET_C(R53.2, R54.1, C25.2, U23.3)
+ NET_C(C25.1, GND)
+ NET_C(U23.2, R52.2, R47.1)
+ NET_C(R52.1, GND)
+ NET_C(R47.2, U23.1, U31.14)
+
+ NET_C(U31.13, U31.5, R10.1)
+ NET_C(U31.12, R49.2)
+ NET_C(U31.15, NOISE)
+ NET_C(U31.1, R48.2)
+ NET_C(R48.1, R49.1, U22.6, R45.2)
+ NET_C(U22.5, GND)
+ NET_C(R45.1, U22.7)
+ AFUNC(DAC_U29, 2, "A0*A1")
+ PARAM(DAC_U29.THRESH, 1e-5)
+ NET_C(DAC_U29.A0, U22.7)
+ NET_C(DAC_U29.A1, I_U29_DAC)
+ NET_C(DAC_U29.Q, R44.2)
+ NET_C(R42.1, R43.1, R44.1, U23.6, R46.1)
+ NET_C(U23.5, GND)
+ NET_C(U23.7, R46.2, U31.4)
+
+#if (USE_AFUNC_MIXING)
+ // This prevents the individual sound nets from combining
+ // at the mixing resistors.
+ AFUNC(MIXFUNC, 4, "(A0+A1+A2+A3)/4")
+ NET_C(MIXFUNC.A0, R7.1)
+ NET_C(MIXFUNC.A1, R10.2)
+ NET_C(MIXFUNC.A2, R9.2)
+ NET_C(MIXFUNC.A3, R8.2)
+ ALIAS(OUTPUT, MIXFUNC.Q)
+#else
+ NET_C(R7.1, R10.2, R9.2, R8.2)
+ ALIAS(OUTPUT, R8.2)
+#endif
+
+ //
+ // Unconnected inputs
+ //
+ NET_C(GND, R7.2)
+ NET_C(GND, U3.2, U3.3, U4.2, U4.3, U5.2, U5.3)
+ NET_C(GND, U17.2, U17.3, U18.2, U18.3, U19.2, U19.3)
+ NET_C(GND, U20.2, U20.3, U21.2, U21.3, U22.2, U22.3)
+
+ // unconnected inputs to analog switch -- what's the right approach?
+ NET_C(GND, U8.2, U8.5, U7.2)
+ NET_C(GND, U15.2, U15.5, U16.2)
+ NET_C(GND, U30.2, U30.5, U31.2)
+/*
+ OPTIMIZE_FRONTIER(R48.1, RES_M(1), 50)
+ OPTIMIZE_FRONTIER(R49.1, RES_M(1), 50)
+ OPTIMIZE_FRONTIER(R18.1, RES_M(1), 50)
+ OPTIMIZE_FRONTIER(R19.1, RES_M(1), 50)
+ OPTIMIZE_FRONTIER(R34.1, RES_M(1), 50)
+ OPTIMIZE_FRONTIER(R35.1, RES_M(1), 50)
+*/
+
+NETLIST_END()
diff --git a/src/mame/audio/nl_segausb.h b/src/mame/audio/nl_segausb.h
new file mode 100644
index 00000000000..ec217540801
--- /dev/null
+++ b/src/mame/audio/nl_segausb.h
@@ -0,0 +1,10 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+#ifndef MAME_AUDIO_NL_SEGAUSB_H
+#define MAME_AUDIO_NL_SEGAUSB_H
+
+#pragma once
+
+NETLIST_EXTERNAL(segausb)
+
+#endif // MAME_AUDIO_NL_SEGAUSB_H
diff --git a/src/mame/audio/nl_spacfury.cpp b/src/mame/audio/nl_spacfury.cpp
new file mode 100644
index 00000000000..797185e9dd0
--- /dev/null
+++ b/src/mame/audio/nl_spacfury.cpp
@@ -0,0 +1,1105 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+
+//
+// Netlist for Space Fury
+//
+// Derived from the schematics in the Space Fury manual.
+//
+// Known problems/issues:
+//
+// * Works pretty well. All sounds trigger.
+//
+// * Very challenging to get running at speed. We have to use
+// the "slow" CA3080 model for the star spin sound, which
+// creates a giant net that dominates time and is sensitive
+// to cheats to reduce timesteps, etc
+//
+
+#include "netlist/devices/net_lib.h"
+#include "nl_spacfury.h"
+
+
+//
+// Optimizations
+//
+
+#define HLE_SHOOT_VCO (1)
+#define SPLIT_SHARED_OSCILLATORS (1)
+#define ENABLE_SPIN_VCO_FRONTIER (1)
+#define ENABLE_NOISE_FRONTIERS (1)
+#define ENABLE_FRONTIERS (1)
+#define UNDERCLOCK_NOISE_GEN (1 && ENABLE_NOISE_FRONTIERS)
+
+
+
+
+//
+// Hacks
+//
+
+#define ADD_CLIPPING_DIODES (1)
+
+
+
+//
+// Local models
+//
+
+#define D_1N914(name) DIODE(name, "1N914")
+#define D_1N4002(name) DIODE(name, "D(IS=65.4p RS=42.2m BV=100 IBV=5.00u CJO=14.8p M=0.333 N=1.36 TT=2.88u)")
+
+// SPICE model taken from https://www.onsemi.com/support/design-resources/models?rpn=2N4401
+#define Q_2N4401(name) QBJT_EB(name, "NPN(Is=26.03f Xti=3 Eg=1.11 Vaf=90.7 Bf=4.292K Ne=1.244 Ise=26.03f Ikf=.2061 Xtb=1.5 Br=1.01 Nc=2 Isc=0 Ikr=0 Rc=.5 Cjc=11.01p Mjc=.3763 Vjc=.75 Fc=.5 Cje=24.07p Mje=.3641 Vje=.75 Tr=233.7n Tf=466.5p Itf=0 Vtf=0 Xtf=0 Rb=10)")
+
+// SPICE model taken from https://www.onsemi.com/support/design-resources/models?rpn=2N4403
+#define Q_2N4403(name) QBJT_EB(name, "PNP(Is=650.6E-18 Xti=3 Eg=1.11 Vaf=115.7 Bf=216.2 Ne=1.829 Ise=58.72f Ikf=1.079 Xtb=1.5 Br=3.578 Nc=2 Isc=0 Ikr=0 Rc=.715 Cjc=14.76p Mjc=.5383 Vjc=.75 Fc=.5 Cje=19.82p Mje=.3357 Vje=.75 Tr=111.6n Tf=603.7p Itf=.65 Vtf=5 Xtf=1.7 Rb=10)")
+
+// JFET transistors not supported, but this should do the trick
+//#define Q_2N4093(name) MOSFET(name, "NMOS(VTO=-1.0)")
+#define Q_2N4093(name) MOSFET(name, "NMOS(VTO=-1 CAPMOD=0)")
+
+#define LM555_DIP NE555_DIP
+#define LM566_DIP NE566_DIP
+
+#define TTL_74LS00_DIP TTL_7400_DIP
+
+
+
+//
+// DIP mappings use the submodels below for CA3080
+//
+#define CA3080_FAST_DIP(name) SUBMODEL(_CA3080_FAST_DIP, name)
+#define CA3080_SLOW_DIP(name) SUBMODEL(_CA3080_SLOW_DIP, name)
+static NETLIST_START(_CA3080_FAST_DIP)
+ ALIAS(2, F.A0) // -
+ ALIAS(3, F.A1) // +
+ ALIAS(4, F.A2) // V-
+ ALIAS(5, RIABC.1) // IB
+ ALIAS(6, VO.OP) // FIXME
+ ALIAS(7, F.A4) // V+
+
+ RES(RI, 26000)
+ NET_C(RI.1, F.A0)
+ NET_C(RI.2, F.A1)
+ // Delivers I0
+ AFUNC(F, 5, "max(-0.5e-3, min(0.5e-3, 19.2 * (A3 - A2) * A0))")
+ RES(RIABC, 1)
+ NET_C(RIABC.2, F.A2)
+ NET_C(RIABC.1, F.A3) // IB
+ VCCS(VO, 1)
+ ANALOG_INPUT(XGND, 0)
+ NET_C(XGND, VO.IN, VO.ON) // FIXME: assume symmetric supply
+ NET_C(F.Q, VO.IP)
+NETLIST_END()
+
+static NETLIST_START(_CA3080_SLOW_DIP)
+//
+// These items are common to several models
+//
+#define CA3080_D(name) DIODE(name, "D(IS=2p RS=5 BV=40 CJO=3p TT=6n)")
+#define CA3080_NPN(name) QBJT_EB(name, "NPN(IS=21.48f XTI=3 EG=1.11 VAF=80 BF=550 ISE=50f NE=1.5 IKF=10m XTB=1.5 BR=.1 ISC=10f NC=2 IKR=3m RC=10 CJC=800f MJC=.3333 VJC=.75 FC=.5 CJE=1.3p MJE=.3333 VJE=.75 TR=30n TF=400P ITF=30m XTF=1 VTF=10 CJS=5.8P MJS=.3333 VJS=.75)")
+#define CA3080_PNP(name) QBJT_EB(name, "PNP(IS=50f XTI=3 EG=1.11 VAF=80 BF=100 ISE=130f NE=1.5 IKF=1m XTB=1.5 BR=1 ISC=0 NC=2 IKR=0 RC=0 CJC=4p MJC=.3333 VJC=.75 FC=.5 CJE=1.4p MJE=.3333 VJE=.75 TR=500n TF=23n ITF=.1 XTF=1 VTF=10 CJS=5.5P MJS=.3333 VJS=.75)")
+
+ CA3080_D(D1)
+ CA3080_D(D2)
+ CA3080_NPN(Q1)
+ CA3080_PNP(Q2)
+ CA3080_PNP(Q3)
+ CA3080_NPN(Q4)
+ CA3080_NPN(Q5)
+ CA3080_PNP(Q6)
+ CA3080_PNP(Q7)
+ CA3080_PNP(Q8)
+ CA3080_PNP(Q9)
+ CA3080_NPN(Q10)
+ CA3080_NPN(Q11)
+ CA3080_NPN(Q12)
+ CA3080_NPN(Q13)
+ CA3080_PNP(Q14)
+ CA3080_PNP(Q15)
+
+ ALIAS(2, Q10.B) // N1
+ ALIAS(3, Q5.B) // N28
+ ALIAS(4, Q1.E) // N13
+ ALIAS(5, Q1.B) // N11
+ ALIAS(6, Q6.C) // N30
+ ALIAS(7, Q8.E) // N8
+ NET_C(Q8.E, Q9.E, Q14.E, Q15.E) // N8
+ NET_C(Q1.B, Q1.C, Q4.B) // N11
+ NET_C(Q1.E, Q4.E, Q11.E, Q12.E) // N13
+ NET_C(Q6.C, Q7.C, Q13.C) // N30
+ NET_C(Q3.B, Q10.C, Q14.C, D1.A) // N1N13
+ NET_C(Q2.E, Q14.B, Q15.C, Q15.B) // N1N15
+ NET_C(Q2.B, Q3.E, D1.K) // N1N17
+ NET_C(Q2.C, Q3.C, Q11.C, Q13.B) // N1N22
+ NET_C(Q5.C, Q6.B, Q9.C, D2.A) // N1N32
+ NET_C(Q6.E, Q7.B, D2.K) // N1N34
+ NET_C(Q7.E, Q8.C, Q8.B, Q9.B) // N1N36
+ NET_C(Q4.C, Q5.E, Q10.E) // N1N52
+ NET_C(Q11.B, Q12.C, Q12.B, Q13.E) // N1N44
+NETLIST_END()
+
+
+
+//
+// Main netlist
+//
+
+NETLIST_START(spacfury)
+
+ SOLVER(Solver, 1000)
+ PARAM(Solver.DYNAMIC_TS, 1)
+ PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 4e-5)
+ // subtle but noticeable effect where the spin "whoosh" is missing
+ // some upper harmonics at 4e-5; however, this is the most demanding
+ // solver in the system and it keeps jumping around as I tweak things
+// PARAM(Solver.Solver_21.DYNAMIC_MIN_TIMESTEP, 2e-5)
+
+ // Overwrite model - the default model uses minimum datasheet
+ // specifications for 5V. These are for 10V and thus closer to the
+ // 12V used in this circuit.
+ NET_MODEL("CD4XXX FAMILY(TYPE=CMOS IVL=0.3 IVH=0.7 OVL=0.05 OVH=0.05 ORL=384 ORH=384)")
+
+ LOCAL_SOURCE(_CA3080_FAST_DIP)
+ LOCAL_SOURCE(_CA3080_SLOW_DIP)
+
+ TTL_INPUT(I_LO_D0, 0)
+ ALIAS(I_CRAFTS_SCALE, I_LO_D0)
+ TTL_INPUT(I_LO_D1, 0)
+ ALIAS(I_MOVING, I_LO_D1)
+ TTL_INPUT(I_LO_D2, 0)
+ ALIAS(I_THRUST, I_LO_D2)
+ TTL_INPUT(I_LO_D6, 0)
+ ALIAS(I_STAR_SPIN, I_LO_D6)
+ TTL_INPUT(I_LO_D7, 0)
+ ALIAS(I_PARTIAL_WARSHIP, I_LO_D7)
+
+ NET_C(GND, I_LO_D0.GND, I_LO_D1.GND, I_LO_D2.GND, I_LO_D6.GND, I_LO_D7.GND)
+ NET_C(I_V5, I_LO_D0.VCC, I_LO_D1.VCC, I_LO_D2.VCC, I_LO_D6.VCC, I_LO_D7.VCC)
+
+ TTL_INPUT(I_HI_D0, 0)
+ ALIAS(I_CRAFTS_JOINING, I_HI_D0)
+ TTL_INPUT(I_HI_D1, 0)
+ ALIAS(I_SHOOT, I_HI_D1)
+ TTL_INPUT(I_HI_D2, 0)
+ ALIAS(I_FIREBALL, I_HI_D2)
+ TTL_INPUT(I_HI_D3, 0)
+ ALIAS(I_SMALL_EXPL, I_HI_D3)
+ TTL_INPUT(I_HI_D4, 0)
+ ALIAS(I_LARGE_EXPL, I_HI_D4)
+ TTL_INPUT(I_HI_D5, 0)
+ ALIAS(I_DOCKING_BANG, I_HI_D5)
+
+ NET_C(GND, I_HI_D0.GND, I_HI_D1.GND, I_HI_D2.GND, I_HI_D3.GND, I_HI_D4.GND, I_HI_D5.GND)
+ NET_C(I_V5, I_HI_D0.VCC, I_HI_D1.VCC, I_HI_D2.VCC, I_HI_D3.VCC, I_HI_D4.VCC, I_HI_D5.VCC)
+
+ RES(R_PSG_1, 1000)
+ RES(R_PSG_2, 1000)
+ RES(R_PSG_3, 1000)
+ NET_C(I_V5, R_PSG_1.1, R_PSG_2.1, R_PSG_3.1)
+
+ ANALOG_INPUT(I_V5, 5)
+ ANALOG_INPUT(I_V12, 12)
+ ANALOG_INPUT(I_VM12, -12)
+
+// RES(R1, RES_K(2.2)) -- part of final amp (not emulated)
+// RES(R2, RES_K(10)) -- part of final amp (not emulated)
+// RES(R4, RES_K(330)) -- part of final amp (not emulated)
+// RES(R5, RES_M(1)) -- part of final amp (not emulated)
+ RES(R6, RES_K(680))
+ RES(R7, RES_K(680))
+ RES(R8, RES_K(10))
+ RES(R9, RES_K(100))
+ RES(R10, 680)
+ RES(R11, RES_K(47))
+ RES(R12, RES_K(47))
+ RES(R13, RES_K(47))
+ RES(R14, RES_M(1))
+// RES(R15, RES_K(100)) -- part of final amp (not emulated)
+ RES(R18, RES_K(10))
+ RES(R19, RES_K(470))
+ RES(R20, RES_K(22))
+ RES(R21, RES_K(47))
+ RES(R22, RES_K(3.9))
+ RES(R23, RES_K(82))
+ RES(R24, RES_K(4.7))
+ RES(R25, RES_K(47))
+ RES(R26, 100)
+ RES(R27, RES_K(100))
+ RES(R28, RES_K(100))
+ RES(R29, RES_K(2.2))
+ RES(R30, RES_K(4.7))
+ RES(R31, RES_K(100))
+ RES(R32, RES_K(100))
+ RES(R33, RES_M(1))
+ RES(R34, RES_K(10))
+ RES(R35, RES_K(680))
+ RES(R36, 680)
+ RES(R37, RES_K(47))
+ RES(R38, RES_K(47))
+ RES(R39, RES_K(2.2))
+ RES(R40, RES_K(47))
+ RES(R41, RES_K(47))
+ RES(R42, RES_K(100))
+ RES(R43, RES_K(2.2))
+ RES(R44, RES_K(100))
+ RES(R45, RES_M(2.2))
+ RES(R46, RES_K(100))
+ RES(R47, RES_K(9.1))
+ RES(R48, 100)
+ RES(R49, RES_K(4.7))
+ RES(R50, RES_K(47))
+ RES(R51, RES_K(10))
+ RES(R52, RES_K(47))
+ RES(R53, RES_K(47))
+ RES(R54, RES_K(100))
+ RES(R55, RES_K(47))
+ RES(R56, RES_K(100))
+ RES(R57, RES_K(47))
+ RES(R58, RES_K(100))
+ RES(R59, RES_K(10))
+ RES(R60, 100)
+ RES(R61, RES_K(9.1))
+ RES(R62, RES_K(100))
+ RES(R63, RES_K(47))
+ RES(R64, RES_K(10))
+ RES(R65, RES_K(470))
+ RES(R66, RES_K(10))
+ RES(R67, 100)
+ RES(R68, RES_K(10))
+ RES(R69, RES_K(22))
+ RES(R70, RES_K(220))
+ RES(R71, RES_K(2.2))
+ RES(R72, RES_K(22))
+ RES(R73, RES_K(330))
+ RES(R74, RES_K(330))
+ RES(R75, RES_K(100))
+ RES(R76, RES_K(10))
+ RES(R77, RES_K(10))
+ RES(R78, RES_K(22))
+ RES(R79, RES_K(10))
+ RES(R80, RES_K(100))
+ RES(R81, RES_K(82))
+ RES(R82, RES_K(39))
+ RES(R83, RES_K(10))
+ RES(R84, RES_K(22))
+ RES(R85, RES_K(47))
+ RES(R86, RES_K(47))
+ RES(R87, RES_K(47))
+ RES(R88, RES_K(100))
+ RES(R89, RES_K(100))
+ RES(R90, RES_K(10))
+ RES(R91, RES_M(1))
+ RES(R92, RES_K(470))
+ RES(R93, RES_K(470))
+ RES(R94, RES_K(220))
+ RES(R95, RES_K(22))
+ RES(R96, RES_K(100))
+ RES(R97, RES_K(100))
+ RES(R98, RES_K(10))
+ RES(R99, RES_K(3.9))
+ RES(R100, RES_K(47))
+ RES(R101, RES_K(2.2))
+ RES(R102, RES_M(1))
+ RES(R103, RES_K(10))
+ RES(R104, RES_K(10))
+ RES(R105, RES_K(100))
+ RES(R106, RES_K(10))
+ RES(R107, RES_K(220))
+ RES(R108, RES_K(220))
+ RES(R109, RES_K(10))
+ RES(R110, 100)
+ RES(R111, RES_K(10))
+ RES(R112, RES_K(470))
+ RES(R113, RES_K(100))
+ RES(R114, RES_K(100))
+ RES(R115, RES_K(100))
+ RES(R116, RES_K(100))
+ RES(R117, RES_K(100))
+ RES(R118, RES_K(100))
+ RES(R119, RES_M(2.2))
+ RES(R120, RES_K(100))
+ RES(R121, RES_K(100))
+ RES(R122, RES_M(2.2))
+ RES(R123, RES_K(22))
+ RES(R124, RES_M(3.9))
+ RES(R125, RES_K(100))
+ RES(R126, RES_K(100))
+ RES(R127, RES_M(2.2))
+ RES(R128, RES_K(22))
+ RES(R129, RES_K(22))
+ RES(R130, RES_K(22))
+ RES(R131, RES_K(10))
+ RES(R132, RES_K(2.2))
+ RES(R133, RES_K(2.2))
+ RES(R135, RES_K(10))
+ RES(R136, RES_K(10))
+ RES(R134, RES_K(10))
+ RES(R137, RES_K(2.2))
+ RES(R138, RES_K(150))
+ RES(R139, RES_K(150))
+ RES(R140, RES_K(2.2))
+ RES(R141, RES_K(220))
+ RES(R142, RES_K(100))
+ RES(R143, RES_K(10))
+ RES(R144, RES_K(220))
+ RES(R146, RES_K(220))
+ RES(R147, 680)
+ RES(R148, RES_K(10))
+ RES(R149, RES_K(220))
+
+// CAP(C1, CAP_U(4.7)) -- part of final amp (not emulated)
+// CAP(C2, CAP_U(0.05))
+// CAP(C3, CAP_U(0.05))
+// CAP(C4, CAP_U(10)) -- part of final amp (not emulated)
+ CAP(C5, CAP_U(0.01))
+ CAP(C6, CAP_U(0.01))
+ CAP(C7, CAP_U(4.7))
+ CAP(C8, CAP_U(0.047))
+// CAP(C9, CAP_U(0.05))
+// CAP(C10, CAP_U(0.05))
+ CAP(C11, CAP_U(0.01))
+ CAP(C12, CAP_U(0.01))
+ CAP(C13, CAP_U(0.01))
+ CAP(C14, CAP_U(0.01))
+ CAP(C15, CAP_U(0.01))
+// CAP(C16, CAP_U(0.05))
+// CAP(C17, CAP_U(0.05))
+ CAP(C18, CAP_U(0.01))
+ CAP(C19, CAP_U(0.047))
+ CAP(C20, CAP_U(0.01))
+ CAP(C21, CAP_U(4.7))
+ CAP(C22, CAP_U(0.05))
+ CAP(C23, CAP_U(0.05))
+ CAP(C24, CAP_U(10))
+// CAP(C25, CAP_U(0.05))
+ CAP(C26, CAP_U(0.0033))
+// CAP(C27, CAP_U(0.05))
+ CAP(C28, CAP_U(0.1))
+ CAP(C29, CAP_U(0.001))
+ CAP(C30, CAP_U(0.0022))
+ CAP(C31, CAP_U(0.022))
+ CAP(C32, CAP_U(10))
+ CAP(C33, CAP_U(0.1))
+ CAP(C34, CAP_U(0.1))
+ CAP(C35, CAP_U(0.0033))
+ CAP(C36, CAP_U(4.7))
+ CAP(C37, CAP_U(0.0022))
+// CAP(C38, CAP_U(0.05))
+// CAP(C39, CAP_U(0.05))
+ CAP(C40, CAP_U(0.047))
+ CAP(C41, CAP_U(0.0047))
+ CAP(C42, CAP_U(0.01))
+ CAP(C43, CAP_U(0.01))
+ CAP(C44, CAP_U(4.7))
+// CAP(C45, CAP_U(0.05))
+// CAP(C46, CAP_U(0.05))
+ CAP(C47, CAP_U(0.047))
+ CAP(C48, CAP_U(4.7))
+ CAP(C49, CAP_U(0.1))
+ CAP(C50, CAP_U(4.7))
+ CAP(C51, CAP_U(0.1))
+ CAP(C52, CAP_U(0.022))
+ CAP(C53, CAP_U(10))
+ CAP(C54, CAP_U(0.1))
+ CAP(C55, CAP_U(100))
+// CAP(C56, CAP_U(0.05))
+ CAP(C57, CAP_U(4.7))
+// CAP(C58, CAP_U(0.05))
+ CAP(C59, CAP_U(0.01))
+ CAP(C60, CAP_U(0.01))
+ CAP(C61, CAP_U(0.047))
+ CAP(C62, CAP_U(0.047))
+ CAP(C63, CAP_U(0.05))
+ CAP(C64, CAP_U(0.05))
+// CAP(C65, CAP_U(0.05))
+ CAP(C66, CAP_U(0.033))
+// CAP(C67, CAP_U(0.05))
+ CAP(C68, CAP_U(0.1))
+ CAP(C69, CAP_U(0.1))
+ CAP(C70, CAP_U(0.1))
+ CAP(C71, CAP_U(0.047))
+ CAP(C72, CAP_P(100))
+ CAP(C73, CAP_U(0.1))
+// CAP(C75, CAP_U(10))
+// CAP(C76, CAP_U(10))
+// CAP(C77, CAP_U(0.1))
+// CAP(C78, CAP_U(0.1))
+// CAP(C79, CAP_U(0.1))
+// CAP(C80, CAP_U(0.1))
+
+ D_1N914(D1)
+ D_1N914(D2)
+ D_1N914(D3)
+ D_1N914(D4)
+ D_1N914(D5)
+ D_1N914(D6)
+ D_1N914(D7)
+ D_1N914(D8)
+ D_1N914(D9)
+ D_1N914(D10)
+ D_1N914(D11)
+ D_1N914(D12)
+ D_1N914(D13)
+ D_1N914(D14)
+ D_1N914(D15)
+ D_1N914(D16)
+
+// Q_2N4093(Q1) -- part of final amp (not emulated)
+ Q_2N4093(Q2)
+ Q_2N4093(Q3)
+ Q_2N4403(Q4)
+ Q_2N4403(Q5)
+ Q_2N4403(Q6)
+ Q_2N4093(Q7)
+ Q_2N4093(Q8)
+ Q_2N4403(Q9)
+ Q_2N4403(Q10)
+ Q_2N4401(Q11)
+ Q_2N4401(Q12)
+ Q_2N4403(Q13)
+
+// TL082_DIP(U1) // Op. Amp. -- part of final amp (not emulated)
+// NET_C(U1.8, I_V12)
+// NET_C(U1.4, I_VM12)
+
+ TL082_DIP(U2) // Op. Amp.
+ NET_C(U2.8, I_V12)
+ NET_C(U2.4, I_VM12)
+
+ CD4069_DIP(U3) // Hex Inverter
+ NET_C(U3.7, GND)
+ NET_C(U3.14, I_V12)
+
+ TL082_DIP(U4) // Op. Amp.
+ NET_C(U4.8, I_V12)
+ NET_C(U4.4, I_VM12)
+
+ TL082_DIP(U5) // Op. Amp.
+ NET_C(U5.8, I_V12)
+ NET_C(U5.4, I_VM12)
+
+ CD4011_DIP(U6) // Quad 2-Input NAND Gates
+ NET_C(U6.7, GND)
+ NET_C(U6.14, I_V12)
+
+ CA3080_SLOW_DIP(U7) // Op. Amp.
+ NET_C(U7.4, I_VM12)
+ NET_C(U7.7, I_V12)
+
+ TL082_DIP(U8) // Op. Amp.
+ NET_C(U8.8, I_V12)
+ NET_C(U8.4, I_VM12)
+
+ MM5837_DIP(U9) // Noise Generator
+#if (UNDERCLOCK_NOISE_GEN)
+ // officially runs at 48-112kHz, but little noticeable difference
+ // in exchange for a big performance boost
+ PARAM(U9.FREQ, 24000)
+
+ // the NOISE_B signal can run even lower, so use a second
+ // MM5837 instance at a lower frequency to drive it; this
+ // second instance doesn't really exist, it just allows us
+ // a bit more performance
+ MM5837_DIP(U9B) // Noise Generator
+ PARAM(U9B.FREQ, 12000)
+#endif
+
+ TL082_DIP(U10) // Op. Amp.
+ NET_C(U10.8, I_V12)
+ NET_C(U10.4, I_VM12)
+
+ CD4024_DIP(U11) // 7-Stage Ripple Binary Counter
+ NET_C(U11.7, GND)
+ NET_C(U11.14, I_V12)
+
+ CA3080_SLOW_DIP(U12) // Op. Amp.
+ NET_C(U12.4, I_VM12)
+ NET_C(U12.7, I_V12)
+
+ TL082_DIP(U13) // Op. Amp.
+ NET_C(U13.8, I_V12)
+ NET_C(U13.4, I_VM12)
+
+ TL082_DIP(U14) // Op. Amp.
+ NET_C(U14.8, I_V12)
+ NET_C(U14.4, I_VM12)
+
+ TL082_DIP(U15) // Op. Amp.
+ NET_C(U15.8, I_V12)
+ NET_C(U15.4, I_VM12)
+
+ TL082_DIP(U16) // Op. Amp.
+ NET_C(U16.8, I_V12)
+ NET_C(U16.4, I_VM12)
+
+ LM555_DIP(U17)
+
+ TL082_DIP(U18) // Op. Amp.
+ NET_C(U18.8, I_V12)
+ NET_C(U18.4, I_VM12)
+
+ CD4069_DIP(U19) // Hex Inverter
+ NET_C(U19.7, GND)
+ NET_C(U19.14, I_V12)
+
+ CD4011_DIP(U20) // Quad 2-Input NAND Gates
+ NET_C(U20.7, GND)
+ NET_C(U20.14, I_V12)
+
+ TL082_DIP(U21) // Op. Amp.
+ NET_C(U21.8, I_V12)
+ NET_C(U21.4, I_VM12)
+
+ CD4011_DIP(U22) // Quad 2-Input NAND Gates
+ NET_C(U22.7, GND)
+ NET_C(U22.14, I_V12)
+
+ TL082_DIP(U23) // Op. Amp.
+ NET_C(U23.8, I_V12)
+ NET_C(U23.4, I_VM12)
+
+// TTL_74LS08_DIP(U25) // Quad 2-Input AND Gates
+// NET_C(U25.7, GND)
+// NET_C(U25.14, I_V5)
+
+ TTL_7407_DIP(U26) // Hex Buffers with High Votage Open-Collector Outputs
+ NET_C(U26.7, GND)
+ NET_C(U26.14, I_V5)
+
+// TTL_74LS10_DIP(U28) // Triple 3-Input NAND Gate
+// NET_C(U28.7, GND)
+// NET_C(U28.14, I_V5)
+
+// TTL_74LS14_DIP(U30)
+// NET_C(U30.7, GND)
+// NET_C(U30.14, I_V5)
+
+ TTL_7406_DIP(U31) // Hex inverter -- currently using a clone of 7416, no open collector behavior
+ NET_C(U31.7, GND)
+ NET_C(U31.14, I_V5)
+
+// TTL_74LS374_DIP(U32) // Octal D-Type Transparent Latches And Edge-Triggered Flip-Flop
+// NET_C(U32.10, GND)
+// NET_C(U32.20, I_V5)
+//
+// TTL_74LS374_DIP(U33) // Octal D-Type Transparent Latches And Edge-Triggered Flip-Flop
+// NET_C(U33.10, GND)
+// NET_C(U33.20, I_V5)
+
+// TTL_74LS30_DIP(U34) // 8-Input NAND Gate
+// NET_C(U34.7, GND)
+// NET_C(U34.14, I_V5)
+
+// TTL_74LS14_DIP(U35)
+// NET_C(U35.7, GND)
+// NET_C(U35.14, I_V5)
+
+ //
+ // Sheet 7, top (Moving)
+ //
+
+ // Pairs of CD4069 are used together with resistors and capacitors
+ // to create oscillators. The formula for the frequency is
+ // 1/1.39*R*C. The following are simulated here:
+ //
+ // #1: R35=680K, C12=0.01uF, Freq=105.80Hz
+ // #2: R6=680K, C11=0.01uF, Freq=105.80Hz
+ // #3: R7=680K, C13=0.01uF, Freq=105.80Hz
+ //
+ // Since these are all the same and components have tolerances,
+ // we use tweaked frequencies for #2 and #3
+
+ CLOCK(O1CLK, 105.8)
+ NET_C(O1CLK.GND, GND)
+ NET_C(O1CLK.VCC, I_V12)
+ NET_C(O1CLK.Q, R56.1)
+ NET_C(GND, R35.1, R35.2, C12.1, C12.2, U3.5, U3.9)
+
+ CLOCK(O2CLK, 105.7)
+ NET_C(O2CLK.GND, GND)
+ NET_C(O2CLK.VCC, I_V12)
+ NET_C(O2CLK.Q, R54.1)
+ NET_C(GND, R6.1, R6.2, C11.1, C11.2, U3.1, U3.3)
+
+ CLOCK(O3CLK, 105.9)
+ NET_C(O3CLK.GND, GND)
+ NET_C(O3CLK.VCC, I_V12)
+ NET_C(O3CLK.Q, R58.1)
+ NET_C(GND, R7.1, R7.2, C13.1, C13.2, U3.13, U3.11)
+
+ NET_C(I_MOVING, U31.13)
+ NET_C(U31.12, R56.2, R54.2, R58.2, R59.1)
+ NET_C(R59.2, C15.2, R36.2, C14.1)
+ NET_C(C15.1, U4.2, R28.2)
+ NET_C(R28.1, U4.1, C14.2, R8.1)
+ NET_C(U4.3, GND, R36.1)
+
+ NET_C(R8.2, C5.2, R10.2, C6.1)
+ NET_C(C5.1, U4.6, R9.2)
+ NET_C(R9.1, U4.7, C6.2)
+ ALIAS(MOVING_SUM, C6.2)
+ NET_C(U4.5, GND, R10.1)
+
+ //
+ // Sheet 7, 2nd from top (Star Spin/Partial Warship)
+ //
+
+#if (SPLIT_SHARED_OSCILLATORS)
+
+ // In the schematics, the below oscillators are shared; however,
+ // connecting them also brings the two nets together, so we just
+ // duplicate the clocks here to help keep the very expensive net
+ // below more isolated.
+
+ CLOCK(O1CLKA, 105.8)
+ NET_C(O1CLKA.GND, GND)
+ NET_C(O1CLKA.VCC, I_V12)
+ NET_C(O1CLKA.Q, R55.2)
+
+ CLOCK(O2CLKB, 105.7)
+ NET_C(O2CLKB.GND, GND)
+ NET_C(O2CLKB.VCC, I_V12)
+ NET_C(O2CLKB.Q, R53.2)
+
+ CLOCK(O3CLKC, 105.9)
+ NET_C(O3CLKC.GND, GND)
+ NET_C(O3CLKC.VCC, I_V12)
+ NET_C(O3CLKC.Q, R57.2)
+
+#else
+
+ NET_C(O1CLK.Q, R55.2)
+ NET_C(O2CLK.Q, R53.2)
+ NET_C(O3CLK.Q, R57.2)
+
+#endif
+
+ NET_C(I_STAR_SPIN, U31.3, U31.1)
+ NET_C(U31.2, R148.1)
+ NET_C(C32.1, I_V12, R62.1, R72.1)
+
+ NET_C(R148.2, C32.2, R62.2, U13.5)
+ NET_C(R72.2, R90.2, R91.1, D6.A)
+ NET_C(R90.1, GND)
+ NET_C(U13.6, U13.7, D5.A)
+ NET_C(D5.K, D6.K, R94.1, R92.1)
+ NET_C(R94.2, R108.2, U16.5)
+ NET_C(R108.1, GND)
+ NET_C(R92.2, U16.6, R107.1, C47.1)
+
+#if (ENABLE_SPIN_VCO_FRONTIER)
+ // split the envelope VCO from the rest of the circuit
+ // to break up a giant net into 2 smaller ones
+ NET_C(C47.2, U16.7, U16.2, TESTFUNC.A0)
+ AFUNC(TESTFUNC, 1, "A0")
+ NET_C(TESTFUNC.Q, R89.1, R88.1)
+#else
+ NET_C(C47.2, U16.7, U16.2, R89.1, R88.1)
+#endif
+
+ NET_C(U16.3, R93.1, R91.2)
+ NET_C(R93.2, U16.1, D10.A)
+ NET_C(D10.K, R106.2)
+ NET_C(R106.1, Q11.B, R133.2)
+ NET_C(R133.1, GND)
+ NET_C(Q11.E, GND)
+ NET_C(Q11.C, R107.2)
+
+ NET_C(I_PARTIAL_WARSHIP, U31.5)
+ NET_C(U31.6, R57.1, R53.1, R55.1, C33.1)
+ NET_C(C33.2, R63.1)
+ NET_C(R63.2, R34.1, R51.2, R64.2, U8.6)
+ NET_C(R34.2, U8.1, C26.2)
+ ALIAS(STAR_SPIN_PARTIAL_WARSHIP_SUM, U8.1)
+ NET_C(C26.1, U8.2, U7.6)
+ NET_C(U8.3, GND)
+ NET_C(U31.4, C34.1)
+ NET_C(NOISE_A, C34.1)
+ NET_C(C34.2, R64.1)
+ NET_C(U8.5, R49.2, R50.1)
+ NET_C(R49.1, GND)
+ NET_C(U8.7, R61.1, R51.1)
+ NET_C(R61.2, R60.2, U12.3)
+ NET_C(R60.1, GND)
+ NET_C(U12.2, GND)
+ NET_C(U12.5, R88.2)
+ NET_C(R89.2, U7.5)
+ NET_C(U7.3, R48.2, R47.2)
+ NET_C(U7.2, GND)
+ NET_C(R48.1, GND)
+ NET_C(R47.1, C35.2, U13.1, R50.2)
+ NET_C(U13.3, GND)
+ NET_C(U13.2, C35.1, U12.6)
+
+ //
+ // Sheet 7, middle (Fireball)
+ //
+
+ NET_C(I_FIREBALL, U26.11)
+ NET_C(U26.10, U22.12, R125.2)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_FIREBALL)
+ NET_C(D_FIREBALL.A, U22.12)
+ NET_C(D_FIREBALL.K, I_V12)
+#endif
+ NET_C(R125.1, I_V12, R124.1)
+ NET_C(R124.2, U22.13, C70.1)
+ NET_C(C70.2, U22.10)
+ NET_C(U22.8, U22.9, U22.11)
+ NET_C(U22.11, R123.1)
+ NET_C(R123.2, D12.A)
+ NET_C(D12.K, R86.1, R87.1, C50.1)
+ NET_C(C50.2, GND)
+ NET_C(R86.2, U14.6, R85.1)
+ NET_C(R87.2, U14.5, D8.K, Q8.D)
+ NET_C(NOISE_B, Q8.G)
+ NET_C(Q8.S, GND)
+ NET_C(D8.A, GND)
+ NET_C(R85.2, R71.1, U14.7)
+ NET_C(R71.2, R70.1, C31.2)
+ NET_C(C31.1, GND)
+ NET_C(R70.2, C30.1, R149.1)
+ NET_C(C30.2, U14.2, U14.1, C44.1)
+ NET_C(R149.2, C29.2, U14.3)
+ NET_C(C29.1, GND)
+ ALIAS(FIREBALL_SUM, C44.2)
+
+ //
+ // Sheet 7, 2nd from bottom (Explosions)
+ //
+
+ NET_C(U9.1, GND)
+ NET_C(U9.4, I_V12)
+ NET_C(U9.2, I_VM12)
+ NET_C(C28.1, R14.2)
+
+#if (UNDERCLOCK_NOISE_GEN)
+
+ NET_C(U9B.1, GND)
+ NET_C(U9B.4, I_V12)
+ NET_C(U9B.2, I_VM12)
+ NET_C(U9B.3, C28.2)
+ // Yes - AFuncs are frontiers as well
+ AFUNC(NOISE_B_FUNC, 1, "A0")
+ NET_C(R14.2, NOISE_B_FUNC.A0)
+ ALIAS(NOISE_B, NOISE_B_FUNC.Q)
+ NET_C(R14.1, GND)
+ // Yes - AFuncs are frontiers as well
+ AFUNC(NOISE_A_FUNC, 1, "A0")
+ NET_C(U9.3, NOISE_A_FUNC.A0)
+ NET_C(R52.1, NOISE_A_FUNC.Q)
+ ALIAS(NOISE_A, R52.2)
+
+#else
+
+#if (ENABLE_NOISE_FRONTIERS)
+ // Yes - AFuncs are frontiers as well
+ AFUNC(NOISE_B_FUNC, 1, "A0")
+ NET_C(R14.2, NOISE_B_FUNC.A0)
+ ALIAS(NOISE_B, NOISE_B_FUNC.Q)
+#else
+ ALIAS(NOISE_B, R14.2)
+#endif
+ NET_C(R14.1, GND)
+#if (ENABLE_NOISE_FRONTIERS)
+ // Yes - AFuncs are frontiers as well
+ AFUNC(NOISE_A_FUNC, 1, "A0")
+ NET_C(U9.3, NOISE_A_FUNC.A0, C28.2)
+ NET_C(R52.1, NOISE_A_FUNC.Q)
+#else
+ NET_C(U9.3, R52.1, C28.2)
+#endif
+ ALIAS(NOISE_A, R52.2)
+
+#endif
+
+ NET_C(I_SMALL_EXPL, U26.13)
+ NET_C(U26.12, R32.2, U6.2)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_SMALL_EXPL)
+ NET_C(D_SMALL_EXPL.A, U6.2)
+ NET_C(D_SMALL_EXPL.K, I_V12)
+#endif
+ NET_C(U6.1, C22.1, R33.2)
+ NET_C(R33.1, I_V12, R45.2, R46.2, R32.1)
+ NET_C(R45.1, C23.2, U6.13)
+ NET_C(R46.1, U6.12, U26.6)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(I_LARGE_EXPL)
+ NET_C(I_LARGE_EXPL.A, U6.12)
+ NET_C(I_LARGE_EXPL.K, I_V12)
+#endif
+ NET_C(I_LARGE_EXPL, U26.5)
+ NET_C(C23.1, U6.10)
+ NET_C(U6.8, U6.9, U6.11)
+ NET_C(U6.11, D3.A)
+ NET_C(D3.K, R43.1)
+ NET_C(R43.2, R42.1, R44.1, C24.1)
+ NET_C(C24.2, C21.2, Q3.S, Q2.S, D4.A, D1.A, C18.2, C20.1, GND)
+ NET_C(R42.2, U5.6, R31.1)
+ NET_C(R31.2, R38.1, U5.7)
+ NET_C(U5.5, R44.2, Q3.D, D4.K)
+ NET_C(Q3.G, NOISE_B)
+ NET_C(R38.2, C19.1, R37.1)
+ NET_C(C19.2, U5.2, U5.1, R29.1)
+ NET_C(R37.2, U5.3, C18.1)
+ NET_C(R29.2, C7.1, R30.1)
+ ALIAS(EXPL_SUM, C7.2)
+
+ NET_C(C22.2, U6.4)
+ NET_C(U6.5, U6.6, D2.A, U6.3)
+ NET_C(D2.K, R39.1)
+ NET_C(R39.2, R41.1, R40.1, C21.1)
+ NET_C(R41.2, U2.6, R13.1)
+ NET_C(R13.2, U2.7, R11.1)
+ NET_C(U2.5, R40.2, Q2.D, D1.K)
+ NET_C(Q2.G, NOISE_B)
+ NET_C(R11.2, C8.1, R12.1)
+ NET_C(R12.2, C20.2, U2.3)
+ NET_C(C8.2, U2.2, U2.1, R30.2)
+
+ //
+ // Sheet 7, bottom-left (PSG)
+ //
+
+ NET_C(R_PSG_1.2, R_PSG_2.2, R_PSG_3.2, R147.2, C73.1)
+ NET_C(R147.1, GND)
+ NET_C(C73.2, R146.1)
+ NET_C(R146.2, U23.2, R141.1, C72.1)
+ NET_C(U23.3, GND)
+ NET_C(C72.2, R141.2, U23.1)
+ ALIAS(PSG_SUM, U23.1)
+
+ //
+ // Sheet 7, bottom (Thrust)
+ //
+
+ NET_C(I_THRUST, U31.11)
+ NET_C(U31.10, R96.1, R97.1, R98.2)
+ NET_C(R98.1, I_V12)
+ NET_C(R96.2, U15.2, R75.1)
+ NET_C(U15.3, R97.2, Q7.D, D7.K)
+ NET_C(Q7.G, NOISE_B)
+ NET_C(Q7.S, GND)
+ NET_C(D7.A, GND)
+ NET_C(U15.1, R75.2, R95.1)
+ NET_C(R95.2, C40.2, R73.1)
+ NET_C(C40.1, GND)
+ NET_C(R73.2, R74.1, C41.1)
+ NET_C(R74.2, C37.2, U15.5)
+ NET_C(C37.1, GND)
+ NET_C(C41.2, U15.6, U15.7, C36.1)
+ ALIAS(THRUST_SUM, C36.2)
+
+ //
+ // Sheet 8, top (Crafts Joining)
+ //
+
+ NET_C(I_CRAFTS_JOINING, U26.1)
+ NET_C(U26.2, R120.1, U20.12)
+ NET_C(R120.2, I_V12, R119.2, C48.1, R80.2, R79.2)
+ NET_C(R119.1, C64.1, U20.13)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_CRAFTS_JOINING)
+ NET_C(D_CRAFTS_JOINING.A, U20.13)
+ NET_C(D_CRAFTS_JOINING.K, I_V12)
+#endif
+ NET_C(U20.11, U20.8, U20.9)
+ NET_C(U20.10, C64.2, D9.K)
+ NET_C(D9.A, R101.1)
+ NET_C(R101.2, C48.2, R80.1, Q6.B)
+ NET_C(Q6.E, R79.1)
+ NET_C(Q6.C, Q5.E, Q4.E)
+
+ // Another set of CD4069 oscillators:
+ //
+ // #4: R138=150K, C61=0.047uF, Freq=102.05Hz
+ // #5: R144=220K, C71=0.047uF, Freq=69.58Hz
+ // #6: R139=150K, C62=0.047uF, Freq=102.05Hz
+
+ CLOCK(O4CLK, 102.05)
+ NET_C(O4CLK.GND, GND)
+ NET_C(O4CLK.VCC, I_V12)
+ NET_C(O4CLK.Q, R115.1, R116.2)
+ NET_C(GND, R138.1, R138.2, C61.1, C61.2, U19.1, U19.3)
+
+ CLOCK(O5CLK, 69.58)
+ NET_C(O5CLK.GND, GND)
+ NET_C(O5CLK.VCC, I_V12)
+ NET_C(O5CLK.Q, R114.1, R117.2)
+ NET_C(GND, R144.1, R144.2, C71.1, C71.2, U19.5, U19.9)
+
+ CLOCK(O6CLK, 102.15)
+ NET_C(O6CLK.GND, GND)
+ NET_C(O6CLK.VCC, I_V12)
+ NET_C(O6CLK.Q, R113.1, R118.2)
+ NET_C(GND, R139.1, R139.2, C62.1, C62.2, U19.13, U19.11)
+
+ NET_C(R115.2, R114.2, R113.2, C43.2, C42.1, R100.2)
+ NET_C(C43.1, R65.1, U10.2)
+ NET_C(U10.3, R100.1, R99.2, U18.5, R67.1, R110.2, R68.1, Q5.B, R134.2, Q9.B, GND)
+ NET_C(R65.2, U10.1, C42.2, R78.1)
+ NET_C(R78.2, Q4.B, R67.2)
+ NET_C(Q4.C, R68.2, R76.1, U10.5)
+ NET_C(Q5.C, R77.1, R66.1, U10.6)
+ NET_C(R76.2, R77.2, I_VM12)
+ NET_C(R66.2, U10.7)
+ ALIAS(JOINING_SUM, U10.7)
+
+ //
+ // Sheet 8, middle (Docking Bang)
+ //
+
+ NET_C(R116.1, R117.1, R118.1, R99.1, C60.1, C59.1)
+ NET_C(C60.2, R112.1, U18.6)
+ NET_C(C59.2, R112.2, U18.7, R111.1)
+ NET_C(R111.2, R110.1, Q10.B)
+ NET_C(Q10.C, R134.1, R135.2, U18.3)
+ NET_C(Q10.E, Q9.E, Q13.C)
+ NET_C(Q9.C, U18.2, R109.1, R136.2)
+ NET_C(R135.1, R136.1, I_VM12)
+ NET_C(R109.2, U18.1)
+ ALIAS(BANG_SUM, U18.1)
+
+ NET_C(I_DOCKING_BANG, U26.3)
+ NET_C(U26.4, R121.2, U20.2)
+ NET_C(R121.1, I_V12, R127.2, R126.2, R122.1, C57.1, R142.1, R143.1)
+ NET_C(R122.2, C63.1, U20.1)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_DOCKING_BANG)
+ NET_C(D_DOCKING_BANG.A, U20.1)
+ NET_C(D_DOCKING_BANG.K, I_V12)
+#endif
+ NET_C(U20.3, U20.5, U20.6)
+ NET_C(U20.4, C63.2, D16.K)
+ NET_C(D16.A, R137.1)
+ NET_C(R137.2, C57.2, R142.2, Q13.B)
+ NET_C(Q13.E, R143.2)
+
+ //
+ // Sheet 8, 2nd from bottom (Shoot)
+ //
+
+ NET_C(I_SHOOT, U26.9)
+ NET_C(U26.8, R126.1, U22.2)
+#if (ADD_CLIPPING_DIODES)
+ // fast retriggering relies on clipping diodes which
+ // aren't implemented by default for speed
+ D_1N914(D_SHOOT)
+ NET_C(D_SHOOT.A, U22.2)
+ NET_C(D_SHOOT.K, I_V12)
+#endif
+ NET_C(U22.1, R127.1, C69.2)
+ NET_C(C69.1, U22.4, U11.2)
+ NET_C(U22.5, U22.6, U22.3)
+ NET_C(U22.3, D14.K)
+ NET_C(D14.A, R140.1)
+ NET_C(R140.2, D15.K, C68.2)
+ NET_C(C68.1, C66.1, D13.A, GND)
+ NET_C(D15.A, R102.1, D13.K) // and U21.3
+ NET_C(C66.2, R103.1) // and U21.2
+ NET_C(R103.2, R102.2, R84.1)// and U21.1
+
+#if (HLE_SHOOT_VCO)
+ //
+ // R2 = 0.96721: HP = (0.000138452*A0) - 0.0000076731
+ // R2 = 0.97638: HP = (0.0000289361*A0*A0) + (0.000074399*A0) + 0.0000125173
+ // R2 = 0.97705: HP = (0.0000152345*A0*A0*A0) - (0.0000278973*A0*A0) + (0.000132881*A0) - 0.00000173354
+ // R2 = 0.97706: HP = (-0.00000384290*A0*A0*A0*A0) + (0.0000353504*A0*A0*A0) - (0.000063189*A0*A0) + (0.000156402*A0) - 0.00000642730
+ // R2 = 0.97712: HP = (0.0000167037*A0*A0*A0*A0*A0) - (0.000115736*A0*A0*A0*A0) + (0.000312133*A0*A0*A0) - (0.000372722*A0*A0) + (0.000308685*A0) - 0.0000319600
+ //
+ VARCLOCK(SHOOTCLK, 1, "max(0.000001,min(0.1,(0.0000152345*A0*A0*A0) - (0.0000278973*A0*A0) + (0.000132881*A0) - 0.00000173354))")
+ NET_C(SHOOTCLK.GND, GND)
+ NET_C(SHOOTCLK.VCC, I_V5)
+ NET_C(SHOOTCLK.A0, D15.K)
+ NET_C(SHOOTCLK.Q, SHOOTENV.A0)
+ AFUNC(SHOOTENV, 1, "if(A0>2.5,11.1,-11.1)")
+ NET_C(SHOOTENV.Q, U11.1)
+ NET_C(GND, U21.3, U21.2)
+#else
+ NET_C(D15.A, U21.3)
+ NET_C(U21.2, C66.2)
+ NET_C(R103.2, U21.1)
+#endif
+
+ NET_C(R84.2, U11.1)
+ NET_C(U11.12, R81.1)
+ NET_C(U11.11, R82.1)
+ NET_C(U11.9, R83.1)
+ NET_C(U11.6, R69.1)
+ NET_C(R81.2, R82.2, R83.2, R69.2, C49.1)
+ ALIAS(SHOOT_SUM, C49.2)
+
+ //
+ // Sheet 8, bottom (Crafts Scale)
+ //
+
+ NET_C(I_CRAFTS_SCALE, U31.9)
+ NET_C(U31.8, R130.1, R129.1, U17.4)
+ NET_C(R130.2, R132.2, C55.1, R104.2, U17.8, C53.1, I_V12)
+ NET_C(R129.2, R128.2, Q12.B)
+ NET_C(Q12.C, D11.A, R131.1, R132.1)
+ NET_C(R128.1, Q12.E, C52.1, U17.1, C54.1, C53.2, GND)
+ NET_C(D11.K, R131.2, C55.2, C54.2, U17.5)
+ NET_C(R104.1, R105.2, U17.7)
+ NET_C(C52.2, U17.6, U17.2, R105.1)
+ NET_C(U17.3, C51.1)
+ ALIAS(SCALE_SUM, C51.2)
+
+ //
+ // Sheet 8, right (summing)
+ //
+
+ NET_C(JOINING_SUM, R25.1)
+ NET_C(BANG_SUM, R21.1)
+ NET_C(SHOOT_SUM, R23.1)
+ NET_C(SCALE_SUM, R19.1)
+ NET_C(EXPL_SUM, R26.1)
+ NET_C(THRUST_SUM, R22.1)
+ NET_C(MOVING_SUM, R27.1)
+ NET_C(FIREBALL_SUM, R24.1)
+ NET_C(STAR_SPIN_PARTIAL_WARSHIP_SUM, R20.1)
+ NET_C(PSG_SUM, R18.1)
+
+ NET_C(R25.2, R21.2, R23.2, R19.2, R26.2, R22.2, R27.2, R24.2, R20.2, R18.2)
+ ALIAS(OUTPUT, R18.2)
+
+ //
+ // Unconnected inputs
+ //
+
+ NET_C(GND, U21.5, U21.6)
+ NET_C(GND, U23.5, U23.6)
+
+ //
+ // Unconnected outputs
+ //
+
+#if (ENABLE_FRONTIERS)
+#define RXX 384
+ OPTIMIZE_FRONTIER(C36.1, RES_K(3.9), RXX)
+ OPTIMIZE_FRONTIER(C44.1, RES_K(4.7), RXX)
+ OPTIMIZE_FRONTIER(R25.1, RES_K(47), RXX)
+ OPTIMIZE_FRONTIER(R21.1, RES_K(47), RXX)
+ OPTIMIZE_FRONTIER(R23.1, RES_K(82), RXX)
+ OPTIMIZE_FRONTIER(R19.1, RES_K(470), RXX)
+ OPTIMIZE_FRONTIER(R26.1, 100, RXX)
+ OPTIMIZE_FRONTIER(R22.1, RES_K(3.9), RXX)
+ OPTIMIZE_FRONTIER(R27.1, RES_K(100), RXX)
+ OPTIMIZE_FRONTIER(R24.1, RES_K(4.7), RXX)
+ OPTIMIZE_FRONTIER(R20.1, RES_K(22), RXX)
+#endif
+
+NETLIST_END()
diff --git a/src/mame/audio/nl_spacfury.h b/src/mame/audio/nl_spacfury.h
new file mode 100644
index 00000000000..f53e47d9674
--- /dev/null
+++ b/src/mame/audio/nl_spacfury.h
@@ -0,0 +1,10 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+#ifndef MAME_AUDIO_NL_SPACFURY_H
+#define MAME_AUDIO_NL_SPACFURY_H
+
+#pragma once
+
+NETLIST_EXTERNAL(spacfury)
+
+#endif // MAME_AUDIO_NL_SPACFURY_H
diff --git a/src/mame/audio/segag80.cpp b/src/mame/audio/segag80.cpp
new file mode 100644
index 00000000000..f3d2d9b9179
--- /dev/null
+++ b/src/mame/audio/segag80.cpp
@@ -0,0 +1,185 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/*************************************************************************
+
+ Sega vector hardware
+
+*************************************************************************/
+
+#include "emu.h"
+
+#include "audio/segag80.h"
+#include "audio/nl_astrob.h"
+#include "audio/nl_elim.h"
+#include "audio/nl_spacfury.h"
+#include "includes/segag80v.h"
+#include "sound/samples.h"
+
+
+
+/*************************************
+ *
+ * Base class
+ *
+ *************************************/
+
+segag80_audio_device::segag80_audio_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 lomask, u8 himask, bool haspsg, void (*netlist)(netlist::nlparse_t &), double output_scale)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_mixer_interface(mconfig, *this)
+ , m_lo_input(*this, "sound_nl:lo_%u", 0)
+ , m_hi_input(*this, "sound_nl:hi_%u", 0)
+ , m_psg(*this, "psg")
+ , m_lo_vals(0xff)
+ , m_hi_vals(0xff)
+ , m_lo_mask(lomask)
+ , m_hi_mask(himask)
+ , m_has_psg(haspsg)
+ , m_netlist(netlist)
+ , m_output_scale(output_scale)
+{
+}
+
+void segag80_audio_device::device_add_mconfig(machine_config &config)
+{
+ NETLIST_SOUND(config, "sound_nl", 48000)
+ .set_source(m_netlist)
+ .add_route(ALL_OUTPUTS, *this, 1.0);
+
+ if (BIT(m_lo_mask, 0))
+ NETLIST_LOGIC_INPUT(config, m_lo_input[0], "I_LO_D0.IN", 0);
+ if (BIT(m_lo_mask, 1))
+ NETLIST_LOGIC_INPUT(config, m_lo_input[1], "I_LO_D1.IN", 0);
+ if (BIT(m_lo_mask, 2))
+ NETLIST_LOGIC_INPUT(config, m_lo_input[2], "I_LO_D2.IN", 0);
+ if (BIT(m_lo_mask, 3))
+ NETLIST_LOGIC_INPUT(config, m_lo_input[3], "I_LO_D3.IN", 0);
+ if (BIT(m_lo_mask, 4))
+ NETLIST_LOGIC_INPUT(config, m_lo_input[4], "I_LO_D4.IN", 0);
+ if (BIT(m_lo_mask, 5))
+ NETLIST_LOGIC_INPUT(config, m_lo_input[5], "I_LO_D5.IN", 0);
+ if (BIT(m_lo_mask, 6))
+ NETLIST_LOGIC_INPUT(config, m_lo_input[6], "I_LO_D6.IN", 0);
+ if (BIT(m_lo_mask, 7))
+ NETLIST_LOGIC_INPUT(config, m_lo_input[7], "I_LO_D7.IN", 0);
+
+ if (BIT(m_hi_mask, 0))
+ NETLIST_LOGIC_INPUT(config, m_hi_input[0], "I_HI_D0.IN", 0);
+ if (BIT(m_hi_mask, 1))
+ NETLIST_LOGIC_INPUT(config, m_hi_input[1], "I_HI_D1.IN", 0);
+ if (BIT(m_hi_mask, 2))
+ NETLIST_LOGIC_INPUT(config, m_hi_input[2], "I_HI_D2.IN", 0);
+ if (BIT(m_hi_mask, 3))
+ NETLIST_LOGIC_INPUT(config, m_hi_input[3], "I_HI_D3.IN", 0);
+ if (BIT(m_hi_mask, 4))
+ NETLIST_LOGIC_INPUT(config, m_hi_input[4], "I_HI_D4.IN", 0);
+ if (BIT(m_hi_mask, 5))
+ NETLIST_LOGIC_INPUT(config, m_hi_input[5], "I_HI_D5.IN", 0);
+ if (BIT(m_hi_mask, 6))
+ NETLIST_LOGIC_INPUT(config, m_hi_input[6], "I_HI_D6.IN", 0);
+ if (BIT(m_hi_mask, 7))
+ NETLIST_LOGIC_INPUT(config, m_hi_input[7], "I_HI_D7.IN", 0);
+
+ if (m_has_psg)
+ {
+ AY8912(config, m_psg, VIDEO_CLOCK/4/2);
+ m_psg->set_flags(AY8910_RESISTOR_OUTPUT);
+ m_psg->set_resistors_load(10000.0, 10000.0, 10000.0);
+ m_psg->add_route(0, "sound_nl", 1.0, 0);
+ m_psg->add_route(1, "sound_nl", 1.0, 1);
+ m_psg->add_route(2, "sound_nl", 1.0, 2);
+
+ NETLIST_STREAM_INPUT(config, "sound_nl:cin0", 0, "R_PSG_1.R");
+ NETLIST_STREAM_INPUT(config, "sound_nl:cin1", 1, "R_PSG_2.R");
+ NETLIST_STREAM_INPUT(config, "sound_nl:cin2", 2, "R_PSG_3.R");
+ }
+
+ NETLIST_STREAM_OUTPUT(config, "sound_nl:cout0", 0, "OUTPUT").set_mult_offset(m_output_scale, 0.0);
+}
+
+void segag80_audio_device::device_start()
+{
+}
+
+void segag80_audio_device::device_stop()
+{
+}
+
+void segag80_audio_device::write(offs_t addr, uint8_t data)
+{
+ addr &= 1;
+
+ auto &inputs = (addr == 0) ? m_lo_input : m_hi_input;
+ auto &oldvals = (addr == 0) ? m_lo_vals : m_hi_vals;
+ auto &mask = (addr == 0) ? m_lo_mask : m_hi_mask;
+
+ for (int bit = 0; bit < 8; bit++)
+ if (BIT(mask, bit))
+ inputs[bit]->write_line(BIT(data, bit));
+ oldvals = data;
+}
+
+void segag80_audio_device::write_ay(offs_t addr, uint8_t data)
+{
+ assert(m_has_psg);
+ m_psg->address_data_w(addr, data);
+}
+
+
+
+/*************************************
+ *
+ * Eliminator
+ *
+ *************************************/
+
+DEFINE_DEVICE_TYPE(ELIMINATOR_AUDIO, elim_audio_device, "elim_audio", "Eliminator Sound Board")
+
+elim_audio_device::elim_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : segag80_audio_device(mconfig, ELIMINATOR_AUDIO, tag, owner, clock, 0xfe, 0xff, false, NETLIST_NAME(elim), 5000.0)
+{
+}
+
+
+
+/*************************************
+ *
+ * Zektor
+ *
+ *************************************/
+
+DEFINE_DEVICE_TYPE(ZEKTOR_AUDIO, zektor_audio_device, "zektor_audio", "Zektor Sound Board")
+
+zektor_audio_device::zektor_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : segag80_audio_device(mconfig, ZEKTOR_AUDIO, tag, owner, clock, 0xfe, 0xff, true, NETLIST_NAME(zektor), 5000.0)
+{
+}
+
+
+
+/*************************************
+ *
+ * Space Fury
+ *
+ *************************************/
+
+DEFINE_DEVICE_TYPE(SPACE_FURY_AUDIO, spacfury_audio_device, "spcfury_audio", "Space Fury Sound Board")
+
+spacfury_audio_device::spacfury_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : segag80_audio_device(mconfig, SPACE_FURY_AUDIO, tag, owner, clock, 0xc7, 0x3f, false, NETLIST_NAME(spacfury), 60000.0)
+{
+}
+
+
+
+/*************************************
+ *
+ * Astro Blaster
+ *
+ *************************************/
+
+DEFINE_DEVICE_TYPE(ASTRO_BLASTER_AUDIO, astrob_audio_device, "astrob_audio", "Astro Blaster Sound Board")
+
+astrob_audio_device::astrob_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : segag80_audio_device(mconfig, ASTRO_BLASTER_AUDIO, tag, owner, clock, 0xff, 0xff, false, NETLIST_NAME(astrob), 25000.0)
+{
+}
diff --git a/src/mame/audio/segag80.h b/src/mame/audio/segag80.h
new file mode 100644
index 00000000000..4f6c29b324a
--- /dev/null
+++ b/src/mame/audio/segag80.h
@@ -0,0 +1,74 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+#ifndef MAME_AUDIO_SEGAG80V_H
+#define MAME_AUDIO_SEGAG80V_H
+
+#pragma once
+
+#include "machine/netlist.h"
+#include "netlist/nl_setup.h"
+#include "sound/ay8910.h"
+
+
+class segag80_audio_device : public device_t, public device_mixer_interface
+{
+public:
+ segag80_audio_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 lomask, u8 himask, bool haspsg, void (*netlist)(netlist::nlparse_t &), double output_scale);
+
+ void write(offs_t addr, uint8_t data);
+ void write_ay(offs_t addr, uint8_t data);
+
+protected:
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_start() override;
+ virtual void device_stop() override;
+
+ optional_device_array<netlist_mame_logic_input_device, 8> m_lo_input;
+ optional_device_array<netlist_mame_logic_input_device, 8> m_hi_input;
+ optional_device<ay8912_device> m_psg;
+
+private:
+ u8 m_lo_vals;
+ u8 m_hi_vals;
+ u8 m_lo_mask;
+ u8 m_hi_mask;
+ bool m_has_psg;
+ void (*m_netlist)(netlist::nlparse_t &) = nullptr;
+ double m_output_scale = 0;
+};
+
+
+class elim_audio_device : public segag80_audio_device
+{
+public:
+ elim_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+};
+
+
+class zektor_audio_device : public segag80_audio_device
+{
+public:
+ zektor_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+};
+
+
+class spacfury_audio_device : public segag80_audio_device
+{
+public:
+ spacfury_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+};
+
+
+class astrob_audio_device : public segag80_audio_device
+{
+public:
+ astrob_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+};
+
+
+DECLARE_DEVICE_TYPE(ELIMINATOR_AUDIO, elim_audio_device)
+DECLARE_DEVICE_TYPE(ZEKTOR_AUDIO, zektor_audio_device)
+DECLARE_DEVICE_TYPE(SPACE_FURY_AUDIO, spacfury_audio_device)
+DECLARE_DEVICE_TYPE(ASTRO_BLASTER_AUDIO, astrob_audio_device)
+
+#endif // MAME_AUDIO_SEGAG80V_H
diff --git a/src/mame/audio/segag80r.cpp b/src/mame/audio/segag80r.cpp
index d71ec7edda9..1662c2f2258 100644
--- a/src/mame/audio/segag80r.cpp
+++ b/src/mame/audio/segag80r.cpp
@@ -88,260 +88,6 @@ void sega005_sound_device::sound_stream_update(sound_stream &stream, stream_samp
/*************************************
*
- * Astro Blaster sound hardware
- *
- *************************************/
-
-/*
- Description of Astro Blaster sounds (in the hope of future discrete goodness):
-
- CD4017 = decade counter with one output per decoded stage (10 outputs altogether)
- CD4024 = 7-bit counter with 7 outputs
-
-
- "V" signal
- ----------
- CD4017 @ U15:
- reset by RATE RESET signal = 1
- clocked by falling edge of ATTACK signal
- +12V output from here goes through a diode and one of 10 resistors:
- 0 = 120k
- 1 = 82k
- 2 = 62k
- 3 = 56k
- 4 = 47k
- 5 = 39k
- 6 = 35k
- 7 = 27k
- 8 = 24k
- 9 = 22k
- and then in series through a 22k resistor
-
- Op-amp @ U6 takes the WARP signal and the output of CD4017 @ U15
- and forms the signal "V" which is used to control the invader
- sounds
-
-
- How to calculate the output voltage at U16 labeled (V).
- (Derrick Renaud)
-
- First you have an inverting amp. To get the gain you
- use G=-Rf/Ri, where Rf=R178=22k. Ri is the selected
- resistor on the output of U15.
-
- The input voltage to the amp (pin 6) will always be
- about 12V - 0.5V (diode drop in low current circuit) =
- 11.5V.
-
- Now you need to calculate the reference voltage on the
- + input (pin 5). Depending on the state of WARP...
-
- If the warp data is 0, then U31 inverts it to an Open
- Collector high, meaning WARP is out of circuit. So:
- Vref = 12V * (R163)/(R162+R163)
- = 12V * 10k/(10K+4.7k)
- = 8.163V
-
- When warp data is 1, then U31 inverts it to low,
- grounding R164 putting it in parallel with R163,
- giving:
- Vref = 12V * (R163||R164)/(R163||R164 +R162)
- = 12V * 5k/(5k+4.7k)
- = 6.186V
-
- Now to get the control voltage V:
- V = (Vi - Vref) * G + Vref
- = (11.5V - Vref) * G + Vref
-
- That gives you the control voltage at V. From there I
- would have to millman the voltage with the internal
- voltage/resistors of the 555 to get the actual used
- control voltage.
-
- But it seems you just want a range, so just use the
- above info to get the highest and lowest voltages
- generated, and create the frequency shift you desire.
- Remember as the control voltage (V) lowers, the
- frequency increases.
-
-
-
- INVADER-1 output
- ----------------
-
-
-
-
- INVADER-2 output
- ----------------
- 555 timer @ U13 in astable mode with the following parameters:
- R1 = 10k
- R2 = 100k
- C = 0.0022u
- CV = "V" signal
- Reset = (PORT076 & 0x02)
- Output goes to CD4024 @ U12
-
- CD4024 @ U12:
- reset through some unknown means
- clocked by 555 timer @ U13
- +12 output from here goes through a resistor ladder:
- Q1 -> 82k
- Q2 -> 39k
- Q3 -> 22k
- Q4 -> 10k
- Summed output from here is INVADER-2
-
-
- INVADER-3 output
- ----------------
- 555 timer at U17 in astable mode with the following parameters:
- R1 = 10k
- R2 = 68k
- C = 0.1u
- CV = some combination of "V" and "W" signals
- Reset = (PORT076 & 0x04)
- Output from here is INVADER-3
-
-*/
-
-static const char *const astrob_sample_names[] =
-{
- "*astrob",
- "invadr1", /* 0 */
- "winvadr1", /* 1 */
- "invadr2", /* 2 */
- "winvadr2", /* 3 */
- "invadr3", /* 4 */
- "winvadr3", /* 5 */
- "invadr4", /* 6 */
- "winvadr4", /* 7 */
- "asteroid", /* 8 */
- "refuel", /* 9 */
- "pbullet", /* 10 */
- "ebullet", /* 11 */
- "eexplode", /* 12 */
- "pexplode", /* 13 */
- "deedle", /* 14 */
- "sonar", /* 15 */
- nullptr
-};
-
-
-void segag80r_state::astrob_sound_board(machine_config &config)
-{
- /* sound hardware */
- SAMPLES(config, m_samples);
- m_samples->set_channels(11);
- m_samples->set_samples_names(astrob_sample_names);
- m_samples->add_route(ALL_OUTPUTS, "speaker", 0.25);
-}
-
-
-/*************************************
- *
- * Astro Blaster sound triggers
- *
- *************************************/
-
-void segag80r_state::astrob_sound_w(offs_t offset, uint8_t data)
-{
- static const float attack_resistor[10] =
- {
- 120.0f, 82.0f, 62.0f, 56.0f, 47.0f, 39.0f, 33.0f, 27.0f, 24.0f, 22.0f
- };
- float freq_factor;
-
- uint8_t diff = data ^ m_sound_state[offset];
- m_sound_state[offset] = data;
-
- switch (offset)
- {
- case 0:
- /* INVADER-1: channel 0 */
- if ((diff & 0x01) && !(data & 0x01)) m_samples->start(0, (data & 0x80) ? 0 : 1, true);
- if ((data & 0x01) && m_samples->playing(0)) m_samples->stop(0);
-
- /* INVADER-2: channel 1 */
- if ((diff & 0x02) && !(data & 0x02)) m_samples->start(1, (data & 0x80) ? 2 : 3, true);
- if ((data & 0x02) && m_samples->playing(1)) m_samples->stop(1);
-
- /* INVADER-3: channel 2 */
- if ((diff & 0x04) && !(data & 0x04)) m_samples->start(2, (data & 0x80) ? 4 : 5, true);
- if ((data & 0x04) && m_samples->playing(2)) m_samples->stop(2);
-
- /* INVADER-4: channel 3 */
- if ((diff & 0x08) && !(data & 0x08)) m_samples->start(3, (data & 0x80) ? 6 : 7, true);
- if ((data & 0x08) && m_samples->playing(3)) m_samples->stop(3);
-
- /* ASTROIDS: channel 4 */
- if ((diff & 0x10) && !(data & 0x10)) m_samples->start(4, 8, true);
- if ((data & 0x10) && m_samples->playing(4)) m_samples->stop(4);
-
- /* MUTE */
- machine().sound().system_mute(data & 0x20);
-
- /* REFILL: channel 5 */
- if (!(data & 0x40) && !m_samples->playing(5)) m_samples->start(5, 9);
- if ( (data & 0x40) && m_samples->playing(5)) m_samples->stop(5);
-
- /* WARP: changes which sample is played for the INVADER samples above */
- if (diff & 0x80)
- {
- if (m_samples->playing(0)) m_samples->start(0, (data & 0x80) ? 0 : 1, true);
- if (m_samples->playing(1)) m_samples->start(1, (data & 0x80) ? 2 : 3, true);
- if (m_samples->playing(2)) m_samples->start(2, (data & 0x80) ? 4 : 5, true);
- if (m_samples->playing(3)) m_samples->start(3, (data & 0x80) ? 6 : 7, true);
- }
- break;
-
- case 1:
- /* LASER #1: channel 6 */
- if ((diff & 0x01) && !(data & 0x01)) m_samples->start(6, 10);
-
- /* LASER #2: channel 7 */
- if ((diff & 0x02) && !(data & 0x02)) m_samples->start(7, 11);
-
- /* SHORT EXPL: channel 8 */
- if ((diff & 0x04) && !(data & 0x04)) m_samples->start(8, 12);
-
- /* LONG EXPL: channel 8 */
- if ((diff & 0x08) && !(data & 0x08)) m_samples->start(8, 13);
-
- /* ATTACK RATE */
- if ((diff & 0x10) && !(data & 0x10)) m_sound_rate = (m_sound_rate + 1) % 10;
-
- /* RATE RESET */
- if (!(data & 0x20)) m_sound_rate = 0;
-
- /* BONUS: channel 9 */
- if ((diff & 0x40) && !(data & 0x40)) m_samples->start(9, 14);
-
- /* SONAR: channel 10 */
- if ((diff & 0x80) && !(data & 0x80)) m_samples->start(10, 15);
- break;
- }
-
- /* the samples were recorded with sound_rate = 0, so we need to scale */
- /* the frequency as a fraction of that; these equations come from */
- /* Derrick's analysis above; we compute the inverted scale factor to */
- /* account for the fact that frequency goes up as CV goes down */
- /* WARP is already taken into account by the differing samples above */
- freq_factor = (11.5f - 8.163f) * (-22.0f / attack_resistor[0]) + 8.163f;
- freq_factor /= (11.5f - 8.163f) * (-22.0f / attack_resistor[m_sound_rate]) + 8.163f;
-
- /* adjust the sample rate of invader sounds based the sound_rate */
- /* this is an approximation */
- if (m_samples->playing(0)) m_samples->set_frequency(0, m_samples->base_frequency(0) * freq_factor);
- if (m_samples->playing(1)) m_samples->set_frequency(1, m_samples->base_frequency(1) * freq_factor);
- if (m_samples->playing(2)) m_samples->set_frequency(2, m_samples->base_frequency(2) * freq_factor);
- if (m_samples->playing(3)) m_samples->set_frequency(3, m_samples->base_frequency(3) * freq_factor);
-}
-
-
-
-/*************************************
- *
* 005 sound hardware
*
*************************************/
diff --git a/src/mame/audio/segag80v.cpp b/src/mame/audio/segag80v.cpp
deleted file mode 100644
index a6944b39d3b..00000000000
--- a/src/mame/audio/segag80v.cpp
+++ /dev/null
@@ -1,327 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-/*************************************************************************
-
- Sega vector hardware
-
-*************************************************************************/
-
-#include "emu.h"
-#include "includes/segag80v.h"
-#include "sound/samples.h"
-
-/* History:
-
-
-
- * 4/25/99 Tac-Scan now makes Credit Noises with $2c (Jim Hernandez)
- * 4/9/99 Zektor Discrete Sound Support mixed with voice samples. (Jim Hernandez)
- Zektor uses some Eliminator sounds.
-
- * 2/5/99 Extra Life sound constant found $1C after fixing main driver. (Jim Hernandez)
- * 1/29/99 Supports Tac Scan new 44.1 kHz sample set. (Jim Hernandez)
-
- * -Stuff to do -
- * Find hex bit for warp.wav sound calls.
- *
- * 2/05/98 now using the new sample_*() functions. BW
- *
- */
-
-/*
- Tac/Scan sound constants
-
- There are some sounds that are unknown:
- $09 Tunnel Warp Sound?
- $0a
- $0b Formation Change
- $0c
- $0e
- $0f
- $1c 1up (Extra Life)
- $2c Credit
- $30 - $3f Hex numbers for ship position flight sounds
- $41
-
- Some sound samples are missing:
- - I use the one bullet and one explosion sound for all 3 for example.
-
-Star Trk Sounds (USB Loaded from 5400 in main EPROMs)
-
-8 PHASER
-a PHOTON
-e TARGETING
-10 DENY
-12 SHEILD HIT
-14 ENTERPRISE HIT
-16 ENT EXPLOSION
-1a KLINGON EXPLOSION
-1c DOCK
-1e STARBASE HIT
-11 STARBASE RED
-22 STARBASE EXPLOSION
-24 SMALL BONUS
-25 LARGE BONUS
-26 STARBASE INTRO
-27 KLINGON INTRO
-28 ENTERPRISE INTRO
-29 PLAYER CHANGE
-2e KLINGON FIRE
-4,5 IMPULSE
-6,7 WARP
-c,d RED ALERT
-18,2f WARP SUCK
-19,2f SAUCER EXIT
-2c,21 NOMAD MOTION
-2d,21 NOMAD STOPPED
-2b COIN DROP MUSIC
-2a HIGH SCORE MUSIC
-
-
-Eliminator Sound Board (800-3174)
----------------------------------
-
-inputs
-0x3c-0x3f
-
-d0 speech ready
-
-outputs ( 0 = ON)
-
-0x3e (076)
-
-d7 torpedo 2
-d6 torpedo 1
-d5 bounce
-d4 explosion 3
-d3 explosion 2
-d2 explosion 1
-d1 fireball
-d0 -
-
-0x3f (077)
-
-d7 background msb
-d6 background lsb
-d5 enemy ship
-d4 skitter
-d3 thrust msb
-d2 thrust lsb
-d1 thrust hi
-d0 thrust lo
-
-Space Fury Sound Board (800-0241)
----------------------------------
-
-0x3e (076) (0 = ON)
-
-d7 partial warship, low frequency oscillation
-d6 star spin
-d5 -
-d4 -
-d3 -
-d2 thrust, low frequency noise
-d1 fire, metalic buzz
-d0 craft scale, rising tone
-
-0x3f (077)
-
-d7 -
-d6 -
-d5 docking bang
-d4 large explosion
-d3 small explosion, low frequency noise
-d2 fireball
-d1 shot
-d0 crafts joining
-
-*/
-
-void segag80v_state::elim1_sh_w(uint8_t data)
-{
- data ^= 0xff;
-
- /* Play fireball sample */
- if (data & 0x02)
- m_samples->start(0, 0);
-
- /* Play explosion samples */
- if (data & 0x04)
- m_samples->start(1, 10);
- if (data & 0x08)
- m_samples->start(1, 9);
- if (data & 0x10)
- m_samples->start(1, 8);
-
- /* Play bounce sample */
- if (data & 0x20)
- {
- if (m_samples->playing(2))
- m_samples->stop(2);
- m_samples->start(2, 1);
- }
-
- /* Play lazer sample */
- if (data & 0xc0)
- {
- if (m_samples->playing(3))
- m_samples->stop(3);
- m_samples->start(3, 5);
- }
-}
-
-void segag80v_state::elim2_sh_w(uint8_t data)
-{
- data ^= 0xff;
-
- /* Play thrust sample */
- if (data & 0x0f)
- m_samples->start(4, 6);
- else
- m_samples->stop(4);
-
- /* Play skitter sample */
- if (data & 0x10)
- m_samples->start(5, 2);
-
- /* Play eliminator sample */
- if (data & 0x20)
- m_samples->start(6, 3);
-
- /* Play electron samples */
- if (data & 0x40)
- m_samples->start(7, 7);
- if (data & 0x80)
- m_samples->start(7, 4);
-}
-
-
-void segag80v_state::zektor1_sh_w(uint8_t data)
-{
- data ^= 0xff;
-
- /* Play fireball sample */
- if (data & 0x02)
- m_samples->start(0, 0);
-
- /* Play explosion samples */
- if (data & 0x04)
- m_samples->start(1, 10);
- if (data & 0x08)
- m_samples->start(1, 9);
- if (data & 0x10)
- m_samples->start(1, 8);
-
- /* Play bounce sample */
- if (data & 0x20)
- {
- if (m_samples->playing(2))
- m_samples->stop(2);
- m_samples->start(2, 1);
- }
-
- /* Play lazer sample */
- if (data & 0xc0)
- {
- if (m_samples->playing(3))
- m_samples->stop(3);
- m_samples->start(3, 5);
- }
-}
-
-void segag80v_state::zektor2_sh_w(uint8_t data)
-{
- data ^= 0xff;
-
- /* Play thrust sample */
- if (data & 0x0f)
- m_samples->start(4, 6);
- else
- m_samples->stop(4);
-
- /* Play skitter sample */
- if (data & 0x10)
- m_samples->start(5, 2);
-
- /* Play eliminator sample */
- if (data & 0x20)
- m_samples->start(6, 3);
-
- /* Play electron samples */
- if (data & 0x40)
- m_samples->start(7, 40);
- if (data & 0x80)
- m_samples->start(7, 41);
-}
-
-
-
-void segag80v_state::spacfury1_sh_w(uint8_t data)
-{
- data ^= 0xff;
-
- /* craft growing */
- if (data & 0x01)
- m_samples->start(1, 0);
-
- /* craft moving */
- if (data & 0x02)
- {
- if (!m_samples->playing(2))
- m_samples->start(2, 1, true);
- }
- else
- m_samples->stop(2);
-
- /* Thrust */
- if (data & 0x04)
- {
- if (!m_samples->playing(3))
- m_samples->start(3, 4, true);
- }
- else
- m_samples->stop(3);
-
- /* star spin */
- if (data & 0x40)
- m_samples->start(4, 8);
-
- /* partial warship? */
- if (data & 0x80)
- m_samples->start(4, 9);
-
-}
-
-void segag80v_state::spacfury2_sh_w(uint8_t data)
-{
- data ^= 0xff;
-
- /* craft joining */
- if (data & 0x01)
- m_samples->start(5, 2);
-
- /* ship firing */
- if (data & 0x02)
- {
- if (m_samples->playing(6))
- m_samples->stop(6);
- m_samples->start(6, 3);
-
- }
-
- /* fireball */
- if (data & 0x04)
- m_samples->start(7, 6);
-
- /* small explosion */
- if (data & 0x08)
- m_samples->start(7, 6);
- /* large explosion */
- if (data & 0x10)
- m_samples->start(7, 5);
-
- /* docking bang */
- if (data & 0x20)
- m_samples->start(0, 7);
-
-}
diff --git a/src/mame/audio/segasnd.cpp b/src/mame/audio/segasnd.cpp
deleted file mode 100644
index af247149188..00000000000
--- a/src/mame/audio/segasnd.cpp
+++ /dev/null
@@ -1,909 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-/***************************************************************************
-
- segasnd.cpp
-
- Sound boards for early Sega G-80 based games.
-
-***************************************************************************/
-
-#include "emu.h"
-#include "segasnd.h"
-
-#include "sound/sp0250.h"
-#include "includes/segag80r.h"
-#include "includes/segag80v.h"
-
-#include <cmath>
-
-
-#define VERBOSE 0
-#include "logmacro.h"
-
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-#define SPEECH_MASTER_CLOCK 3120000
-
-#define USB_MASTER_CLOCK 6000000
-#define USB_2MHZ_CLOCK (USB_MASTER_CLOCK/3)
-#define USB_PCS_CLOCK (USB_2MHZ_CLOCK/2)
-#define USB_GOS_CLOCK (USB_2MHZ_CLOCK/16/4)
-#define MM5837_CLOCK 100000
-
-#define SAMPLE_RATE (USB_2MHZ_CLOCK/8)
-
-
-
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-
-inline void usb_sound_device::g80_filter_state::configure(double r, double c)
-{
- capval = 0.0;
- exponent = 1.0 - std::exp(-1.0 / (r * c * SAMPLE_RATE));
-}
-
-
-inline double usb_sound_device::g80_filter_state::step_rc(double input)
-{
- return capval += (input - capval) * exponent;
-}
-
-
-inline double usb_sound_device::g80_filter_state::step_cr(double input)
-{
- double const result = input - capval;
- capval += result * exponent;
- return result;
-}
-
-
-
-/***************************************************************************
- SPEECH BOARD
-***************************************************************************/
-
-DEFINE_DEVICE_TYPE(SEGASPEECH, speech_sound_device, "sega_speech_sound", "Sega Speech Sound Board")
-
-#define SEGASPEECH_REGION "speech"
-
-speech_sound_device::speech_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : device_t(mconfig, SEGASPEECH, tag, owner, clock),
- device_sound_interface(mconfig, *this),
- m_int_cb(*this),
- m_speech(*this, SEGASPEECH_REGION),
- m_drq(0),
- m_latch(0),
- m_t0(0),
- m_p2(0)
-{
-}
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void speech_sound_device::device_start()
-{
- m_int_cb.resolve();
-
- save_item(NAME(m_latch));
- save_item(NAME(m_t0));
- save_item(NAME(m_p2));
- save_item(NAME(m_drq));
-}
-
-
-/*************************************
- *
- * i8035 port accessors
- *
- *************************************/
-
-
-
-READ_LINE_MEMBER( speech_sound_device::t0_r )
-{
- return m_t0;
-}
-
-READ_LINE_MEMBER( speech_sound_device::t1_r )
-{
- return m_drq;
-}
-
-uint8_t speech_sound_device::p1_r()
-{
- return m_latch & 0x7f;
-}
-
-uint8_t speech_sound_device::rom_r(offs_t offset)
-{
- return m_speech->base()[0x100 * (m_p2 & 0x3f) + offset];
-}
-
-void speech_sound_device::p1_w(uint8_t data)
-{
- if (!(data & 0x80))
- m_t0 = 0;
-}
-
-void speech_sound_device::p2_w(uint8_t data)
-{
- m_p2 = data;
-}
-
-
-
-/*************************************
- *
- * i8035 port accessors
- *
- *************************************/
-
-WRITE_LINE_MEMBER(speech_sound_device::drq_w)
-{
- m_drq = (state == ASSERT_LINE);
-}
-
-
-
-/*************************************
- *
- * External access
- *
- *************************************/
-
-TIMER_CALLBACK_MEMBER( speech_sound_device::delayed_speech_w )
-{
- int data = param;
- u8 old = m_latch;
-
- /* all 8 bits are latched */
- m_latch = data;
-
- /* the high bit goes directly to the INT line */
- m_int_cb((data & 0x80) ? CLEAR_LINE : ASSERT_LINE);
-
- /* a clock on the high bit clocks a 1 into T0 */
- if (!(old & 0x80) && (data & 0x80))
- m_t0 = 1;
-}
-
-
-void speech_sound_device::data_w(uint8_t data)
-{
- machine().scheduler().synchronize(timer_expired_delegate(FUNC(speech_sound_device::delayed_speech_w), this), data);
-}
-
-
-void speech_sound_device::control_w(uint8_t data)
-{
- LOG("Speech control = %X\n", data);
-}
-
-
-//-------------------------------------------------
-// sound_stream_update - handle a stream update
-//-------------------------------------------------
-
-void speech_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
-{
-}
-
-/*************************************
- *
- * Speech board functions
- *
- *************************************/
-
-WRITE_LINE_MEMBER(segag80snd_common::segaspeech_int_w)
-{
- m_audiocpu->set_input_line(0, state);
-}
-
-/*************************************
- *
- * Speech board address maps
- *
- *************************************/
-
-void segag80snd_common::speech_map(address_map &map)
-{
- map(0x0000, 0x07ff).mirror(0x0800).rom();
-}
-
-
-void segag80snd_common::speech_portmap(address_map &map)
-{
- map(0x00, 0xff).r("segaspeech", FUNC(speech_sound_device::rom_r));
- map(0x00, 0xff).w("speech", FUNC(sp0250_device::write));
-}
-
-
-/*************************************
- *
- * Speech board machine drivers
- *
- *************************************/
-
-void segag80snd_common::sega_speech_board(machine_config &config)
-{
- /* CPU for the speech board */
- i8035_device &audiocpu(I8035(config, m_audiocpu, SPEECH_MASTER_CLOCK)); /* divide by 15 in CPU */
- audiocpu.set_addrmap(AS_PROGRAM, &segag80snd_common::speech_map);
- audiocpu.set_addrmap(AS_IO, &segag80snd_common::speech_portmap);
- audiocpu.p1_in_cb().set("segaspeech", FUNC(speech_sound_device::p1_r));
- audiocpu.p1_out_cb().set("segaspeech", FUNC(speech_sound_device::p1_w));
- audiocpu.p2_out_cb().set("segaspeech", FUNC(speech_sound_device::p2_w));
- audiocpu.t0_in_cb().set("segaspeech", FUNC(speech_sound_device::t0_r));
- audiocpu.t1_in_cb().set("segaspeech", FUNC(speech_sound_device::t1_r));
-
- /* sound hardware */
- SEGASPEECH(config, "segaspeech", 0).int_cb().set(FUNC(segag80snd_common::segaspeech_int_w));
- sp0250_device &speech(SP0250(config, "speech", SPEECH_MASTER_CLOCK));
- speech.drq().set("segaspeech", FUNC(speech_sound_device::drq_w));
- speech.add_route(ALL_OUTPUTS, "speaker", 1.0);
-}
-
-
-
-/***************************************************************************
- UNIVERSAL SOUND BOARD
-***************************************************************************/
-
-DEFINE_DEVICE_TYPE(SEGAUSB, usb_sound_device, "segausb", "Sega Universal Sound Board")
-
-usb_sound_device::usb_sound_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
- : device_t(mconfig, type, tag, owner, clock),
- device_sound_interface(mconfig, *this),
- m_ourcpu(*this, "ourcpu"),
- m_maincpu(*this, finder_base::DUMMY_TAG),
- m_stream(nullptr),
- m_in_latch(0),
- m_out_latch(0),
- m_last_p2_value(0),
- m_program_ram(*this, "pgmram"),
- m_work_ram(*this, "workram"),
- m_work_ram_bank(0),
- m_t1_clock(0),
- m_t1_clock_mask(0),
- m_noise_shift(0),
- m_noise_state(0),
- m_noise_subcount(0)
-{
-}
-
-usb_sound_device::usb_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : usb_sound_device(mconfig, SEGAUSB, tag, owner, clock)
-{
-}
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void usb_sound_device::device_start()
-{
- /* create a sound stream */
- m_stream = machine().sound().stream_alloc(*this, 0, 1, SAMPLE_RATE);
-
- /* initialize state */
- m_noise_shift = 0x15555;
-
- for (timer8253 &g : m_timer_group)
- {
- g.chan_filter[0].configure(10e3, 1e-6);
- g.chan_filter[1].configure(10e3, 1e-6);
- g.gate1.configure(100e3, 0.01e-6);
- g.gate2.configure(2 * 100e3, 0.01e-6);
- }
-
- g80_filter_state temp;
- temp.configure(100e3, 0.01e-6);
- m_gate_rc1_exp[0] = temp.exponent;
- temp.configure(1e3, 0.01e-6);
- m_gate_rc1_exp[1] = temp.exponent;
- temp.configure(2 * 100e3, 0.01e-6);
- m_gate_rc2_exp[0] = temp.exponent;
- temp.configure(2 * 1e3, 0.01e-6);
- m_gate_rc2_exp[1] = temp.exponent;
-
- m_noise_filters[0].configure(2.7e3 + 2.7e3, 1.0e-6);
- m_noise_filters[1].configure(2.7e3 + 1e3, 0.30e-6);
- m_noise_filters[2].configure(2.7e3 + 270, 0.15e-6);
- m_noise_filters[3].configure(2.7e3 + 0, 0.082e-6);
- m_noise_filters[4].configure(33e3, 0.1e-6);
-
- m_final_filter.configure(100e3, 4.7e-6);
-
- /* register for save states */
- save_item(NAME(m_in_latch));
- save_item(NAME(m_out_latch));
- save_item(NAME(m_last_p2_value));
- save_item(NAME(m_work_ram_bank));
- save_item(NAME(m_t1_clock));
-
- for (int tgroup = 0; tgroup < 3; tgroup++)
- {
- timer8253 *group = &m_timer_group[tgroup];
- for (int tchan = 0; tchan < 3; tchan++)
- {
- timer8253::channel *channel = &group->chan[tchan];
- save_item(NAME(channel->holding), tgroup * 3 + tchan);
- save_item(NAME(channel->latchmode), tgroup * 3 + tchan);
- save_item(NAME(channel->latchtoggle), tgroup * 3 + tchan);
- save_item(NAME(channel->clockmode), tgroup * 3 + tchan);
- save_item(NAME(channel->bcdmode), tgroup * 3 + tchan);
- save_item(NAME(channel->output), tgroup * 3 + tchan);
- save_item(NAME(channel->lastgate), tgroup * 3 + tchan);
- save_item(NAME(channel->gate), tgroup * 3 + tchan);
- save_item(NAME(channel->subcount), tgroup * 3 + tchan);
- save_item(NAME(channel->count), tgroup * 3 + tchan);
- save_item(NAME(channel->remain), tgroup * 3 + tchan);
- }
- save_item(NAME(group->env), tgroup);
- save_item(NAME(group->chan_filter[0].capval), tgroup);
- save_item(NAME(group->chan_filter[1].capval), tgroup);
- save_item(NAME(group->gate1.capval), tgroup);
- save_item(NAME(group->gate2.capval), tgroup);
- save_item(NAME(group->config), tgroup);
- }
-
- save_item(NAME(m_timer_mode));
- save_item(NAME(m_noise_shift));
- save_item(NAME(m_noise_state));
- save_item(NAME(m_noise_subcount));
- save_item(NAME(m_final_filter.capval));
- save_item(NAME(m_noise_filters[0].capval));
- save_item(NAME(m_noise_filters[1].capval));
- save_item(NAME(m_noise_filters[2].capval));
- save_item(NAME(m_noise_filters[3].capval));
- save_item(NAME(m_noise_filters[4].capval));
-}
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void usb_sound_device::device_reset()
-{
- /* halt the USB CPU at reset time */
- m_ourcpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
-
- /* start the clock timer */
- m_t1_clock_mask = 0x10;
-}
-
-/*************************************
- *
- * Initialization/reset
- *
- *************************************/
-
-TIMER_DEVICE_CALLBACK_MEMBER( usb_sound_device::increment_t1_clock_timer_cb )
-{
- /* only increment if it is not being forced clear */
- if (!(m_last_p2_value & 0x80))
- m_t1_clock++;
-}
-
-/*************************************
- *
- * External access
- *
- *************************************/
-
-uint8_t usb_sound_device::status_r()
-{
- LOG("%s:usb_data_r = %02X\n", machine().describe_context(), (m_out_latch & 0x81) | (m_in_latch & 0x7e));
-
- m_maincpu->adjust_icount(-200);
-
- /* only bits 0 and 7 are controlled by the I8035; the remaining */
- /* bits 1-6 reflect the current input latch values */
- return (m_out_latch & 0x81) | (m_in_latch & 0x7e);
-}
-
-
-TIMER_CALLBACK_MEMBER( usb_sound_device::delayed_usb_data_w )
-{
- int data = param;
-
- /* look for rising/falling edges of bit 7 to control the RESET line */
- m_ourcpu->set_input_line(INPUT_LINE_RESET, (data & 0x80) ? ASSERT_LINE : CLEAR_LINE);
-
- /* if the CLEAR line is set, the low 7 bits of the input are ignored */
- if ((m_last_p2_value & 0x40) == 0)
- data &= ~0x7f;
-
- /* update the effective input latch */
- m_in_latch = data;
-}
-
-
-void usb_sound_device::data_w(uint8_t data)
-{
- LOG("%s:usb_data_w = %02X\n", machine().describe_context(), data);
- machine().scheduler().synchronize(timer_expired_delegate(FUNC(usb_sound_device::delayed_usb_data_w), this), data);
-
- /* boost the interleave so that sequences can be sent */
- machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(250));
-}
-
-
-uint8_t usb_sound_device::ram_r(offs_t offset)
-{
- return m_program_ram[offset];
-}
-
-
-void usb_sound_device::ram_w(offs_t offset, uint8_t data)
-{
- if (m_in_latch & 0x80)
- m_program_ram[offset] = data;
- else
- LOG("%s:sega_usb_ram_w(%03X) = %02X while /LOAD disabled\n", machine().describe_context(), offset, data);
-}
-
-
-
-/*************************************
- *
- * I8035 port accesses
- *
- *************************************/
-
-uint8_t usb_sound_device::p1_r()
-{
- /* bits 0-6 are inputs and map to bits 0-6 of the input latch */
- if ((m_in_latch & 0x7f) != 0)
- LOG("%s: P1 read = %02X\n", machine().describe_context(), m_in_latch & 0x7f);
- return m_in_latch & 0x7f;
-}
-
-
-void usb_sound_device::p1_w(uint8_t data)
-{
- /* bit 7 maps to bit 0 on the output latch */
- m_out_latch = (m_out_latch & 0xfe) | (data >> 7);
- LOG("%s: P1 write = %02X\n", machine().describe_context(), data);
-}
-
-
-void usb_sound_device::p2_w(uint8_t data)
-{
- u8 old = m_last_p2_value;
- m_last_p2_value = data;
-
- /* low 2 bits control the bank of work RAM we are addressing */
- m_work_ram_bank = data & 3;
-
- /* bit 6 controls the "ready" bit output to the host */
- /* it also clears the input latch from the host (active low) */
- m_out_latch = ((data & 0x40) << 1) | (m_out_latch & 0x7f);
- if ((data & 0x40) == 0)
- m_in_latch = 0;
-
- /* bit 7 controls the reset on the upper counter at U33 */
- if ((old & 0x80) && !(data & 0x80))
- m_t1_clock = 0;
-
- LOG("%s: P2 write -> bank=%d ready=%d clock=%d\n", machine().describe_context(), data & 3, (data >> 6) & 1, (data >> 7) & 1);
-}
-
-
-READ_LINE_MEMBER( usb_sound_device::t1_r )
-{
- /* T1 returns 1 based on the value of the T1 clock; the exact */
- /* pattern is determined by one or more jumpers on the board. */
- return (m_t1_clock & m_t1_clock_mask) != 0;
-}
-
-
-
-/*************************************
- *
- * Sound generation
- *
- *************************************/
-
-inline void usb_sound_device::timer8253::channel::clock()
-{
- u8 const old_lastgate = lastgate;
-
- /* update the gate */
- lastgate = gate;
-
- /* if we're holding, skip */
- if (holding)
- return;
-
- /* switch off the clock mode */
- switch (clockmode)
- {
- /* oneshot; waits for trigger to restart */
- case 1:
- if (!old_lastgate && gate)
- {
- output = 0;
- remain = count;
- }
- else
- {
- if (--remain == 0)
- output = 1;
- }
- break;
-
- /* square wave: counts down by 2 and toggles output */
- case 3:
- remain = (remain - 1) & ~1;
- if (remain == 0)
- {
- output ^= 1;
- remain = count;
- }
- break;
- }
-}
-
-
-/*************************************
- *
- * USB timer and envelope controls
- *
- *************************************/
-
-void usb_sound_device::timer_w(int which, u8 offset, u8 data)
-{
- timer8253 *g = &m_timer_group[which];
- timer8253::channel *ch;
- int was_holding;
-
- m_stream->update();
-
- /* switch off the offset */
- switch (offset)
- {
- case 0:
- case 1:
- case 2:
- ch = &g->chan[offset];
- was_holding = ch->holding;
-
- /* based on the latching mode */
- switch (ch->latchmode)
- {
- case 1: /* low word only */
- ch->count = data;
- ch->holding = false;
- break;
-
- case 2: /* high word only */
- ch->count = data << 8;
- ch->holding = false;
- break;
-
- case 3: /* low word followed by high word */
- if (ch->latchtoggle == 0)
- {
- ch->count = (ch->count & 0xff00) | (data & 0x00ff);
- ch->latchtoggle = 1;
- }
- else
- {
- ch->count = (ch->count & 0x00ff) | (data << 8);
- ch->holding = false;
- ch->latchtoggle = 0;
- }
- break;
- }
-
- /* if we're not holding, load the initial count for some modes */
- if (was_holding && !ch->holding)
- ch->remain = 1;
- break;
-
- case 3:
- /* break out the components */
- if (((data & 0xc0) >> 6) < 3)
- {
- ch = &g->chan[(data & 0xc0) >> 6];
-
- /* extract the bits */
- ch->holding = true;
- ch->latchmode = (data >> 4) & 3;
- ch->clockmode = (data >> 1) & 7;
- ch->bcdmode = (data >> 0) & 1;
- ch->latchtoggle = 0;
- ch->output = (ch->clockmode == 1);
- }
- break;
- }
-}
-
-
-void usb_sound_device::env_w(int which, u8 offset, u8 data)
-{
- timer8253 *g = &m_timer_group[which];
-
- m_stream->update();
-
- if (offset < 3)
- g->env[offset] = (double)data;
- else
- g->config = data & 1;
-}
-
-
-
-/*************************************
- *
- * USB work RAM access
- *
- *************************************/
-
-uint8_t usb_sound_device::workram_r(offs_t offset)
-{
- offset += 256 * m_work_ram_bank;
- return m_work_ram[offset];
-}
-
-
-void usb_sound_device::workram_w(offs_t offset, uint8_t data)
-{
- offset += 256 * m_work_ram_bank;
- m_work_ram[offset] = data;
-
- /* writes to the low 32 bytes go to various controls */
- switch (offset & ~3)
- {
- case 0x00: /* CTC0 */
- timer_w(0, offset & 3, data);
- break;
-
- case 0x04: /* ENV0 */
- env_w(0, offset & 3, data);
- break;
-
- case 0x08: /* CTC1 */
- timer_w(1, offset & 3, data);
- break;
-
- case 0x0c: /* ENV1 */
- env_w(1, offset & 3, data);
- break;
-
- case 0x10: /* CTC2 */
- timer_w(2, offset & 3, data);
- break;
-
- case 0x14: /* ENV2 */
- env_w(2, offset & 3, data);
- break;
- }
-}
-
-//-------------------------------------------------
-// sound_stream_update - handle a stream update
-//-------------------------------------------------
-
-void usb_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
-{
- stream_sample_t *dest = outputs[0];
-
- /* iterate over samples */
- while (samples--)
- {
- double noiseval;
- double sample = 0;
- int group;
- int step;
-
-
- /*----------------
- Noise Source
- ----------------
-
- RC
- MM5837 ---> FILTER ---> CR FILTER ---> 3.2x AMP ---> NOISE
- LADDER
- */
-
- /* update the noise source */
- for (step = USB_2MHZ_CLOCK / SAMPLE_RATE; step >= m_noise_subcount; step -= m_noise_subcount)
- {
- m_noise_shift = (m_noise_shift << 1) | (((m_noise_shift >> 13) ^ (m_noise_shift >> 16)) & 1);
- m_noise_state = (m_noise_shift >> 16) & 1;
- m_noise_subcount = USB_2MHZ_CLOCK / MM5837_CLOCK;
- }
- m_noise_subcount -= step;
-
- /* update the filtered noise value -- this is just an approximation to the pink noise filter */
- /* being applied on the PCB, but it sounds pretty close */
- m_noise_filters[0].capval = 0.99765 * m_noise_filters[0].capval + m_noise_state * 0.0990460;
- m_noise_filters[1].capval = 0.96300 * m_noise_filters[1].capval + m_noise_state * 0.2965164;
- m_noise_filters[2].capval = 0.57000 * m_noise_filters[2].capval + m_noise_state * 1.0526913;
- noiseval = m_noise_filters[0].capval + m_noise_filters[1].capval + m_noise_filters[2].capval + m_noise_state * 0.1848;
-
- /* final output goes through a CR filter; the scaling factor is arbitrary to get the noise to the */
- /* correct relative volume */
- noiseval = m_noise_filters[4].step_cr(noiseval);
- noiseval *= 0.075;
-
- /* there are 3 identical groups of circuits, each with its own 8253 */
- for (group = 0; group < 3; group++)
- {
- timer8253 *g = &m_timer_group[group];
- double chan0, chan1, chan2, mix;
-
-
- /*-------------
- Channel 0
- -------------
-
- 8253 CR AD7524
- OUT0 ---> FILTER ---> BUFFER---> VRef ---> 100k ---> mix
- */
-
- /* channel 0 clocks with the PCS clock */
- for (step = USB_2MHZ_CLOCK / SAMPLE_RATE; step >= g->chan[0].subcount; step -= g->chan[0].subcount)
- {
- g->chan[0].subcount = USB_2MHZ_CLOCK / USB_PCS_CLOCK;
- g->chan[0].gate = 1;
- g->chan[0].clock();
- }
- g->chan[0].subcount -= step;
-
- /* channel 0 is mixed in with a resistance of 100k */
- chan0 = g->chan_filter[0].step_cr(g->chan[0].output) * g->env[0] * (1.0/100.0);
-
-
- /*-------------
- Channel 1
- -------------
-
- 8253 CR AD7524
- OUT1 ---> FILTER ---> BUFFER---> VRef ---> 100k ---> mix
- */
-
- /* channel 1 clocks with the PCS clock */
- for (step = USB_2MHZ_CLOCK / SAMPLE_RATE; step >= g->chan[1].subcount; step -= g->chan[1].subcount)
- {
- g->chan[1].subcount = USB_2MHZ_CLOCK / USB_PCS_CLOCK;
- g->chan[1].gate = 1;
- g->chan[1].clock();
- }
- g->chan[1].subcount -= step;
-
- /* channel 1 is mixed in with a resistance of 100k */
- chan1 = g->chan_filter[1].step_cr(g->chan[1].output) * g->env[1] * (1.0/100.0);
-
-
- /*-------------
- Channel 2
- -------------
-
- If timer_mode == 0:
-
- SWITCHED AD7524
- NOISE ---> RC ---> 1.56x AMP ---> INVERTER ---> VRef ---> 33k ---> mix
- FILTERS
-
- If timer mode == 1:
-
- AD7524 SWITCHED
- NOISE ---> INVERTER ---> VRef ---> 33k ---> mix ---> INVERTER ---> RC ---> 1.56x AMP ---> finalmix
- FILTERS
- */
-
- /* channel 2 clocks with the 2MHZ clock and triggers with the GOS clock */
- for (step = 0; step < USB_2MHZ_CLOCK / SAMPLE_RATE; step++)
- {
- if (g->chan[2].subcount-- == 0)
- {
- g->chan[2].subcount = USB_2MHZ_CLOCK / USB_GOS_CLOCK / 2 - 1;
- g->chan[2].gate = !g->chan[2].gate;
- }
- g->chan[2].clock();
- }
-
- /* the exponents for the gate filters are determined by channel 2's output */
- g->gate1.exponent = m_gate_rc1_exp[g->chan[2].output];
- g->gate2.exponent = m_gate_rc2_exp[g->chan[2].output];
-
- /* based on the envelope mode, we do one of two things with source 2 */
- if (g->config == 0)
- {
- chan2 = g->gate2.step_rc(g->gate1.step_rc(noiseval)) * -1.56 * g->env[2] * (1.0/33.0);
- mix = chan0 + chan1 + chan2;
- }
- else
- {
- chan2 = -noiseval * g->env[2] * (1.0/33.0);
- mix = chan0 + chan1 + chan2;
- mix = g->gate2.step_rc(g->gate1.step_rc(-mix)) * 1.56;
- }
-
- /* accumulate the sample */
- sample += mix;
- }
-
-
- /*-------------
- Final mix
- -------------
-
- INPUTS
- EQUAL ---> 1.2x INVERTER ---> CR FILTER ---> out
- WEIGHT
-
- */
- *dest++ = 4000 * m_final_filter.step_cr(sample);
- }
-}
-
-
-/*************************************
- *
- * USB address maps
- *
- *************************************/
-
-void usb_sound_device::usb_map(address_map &map)
-{
- map(0x0000, 0x0fff).ram().share("pgmram");
-}
-
-void usb_sound_device::usb_portmap(address_map &map)
-{
- map(0x00, 0xff).rw(FUNC(usb_sound_device::workram_r), FUNC(usb_sound_device::workram_w)).share("workram");
-}
-
-
-//-------------------------------------------------
-// device_add_mconfig - add device configuration
-//-------------------------------------------------
-
-void usb_sound_device::device_add_mconfig(machine_config &config)
-{
- /* CPU for the usb board */
- I8035(config, m_ourcpu, USB_MASTER_CLOCK); /* divide by 15 in CPU */
- m_ourcpu->set_addrmap(AS_PROGRAM, &usb_sound_device::usb_map);
- m_ourcpu->set_addrmap(AS_IO, &usb_sound_device::usb_portmap);
- m_ourcpu->p1_in_cb().set(FUNC(usb_sound_device::p1_r));
- m_ourcpu->p1_out_cb().set(FUNC(usb_sound_device::p1_w));
- m_ourcpu->p2_out_cb().set(FUNC(usb_sound_device::p2_w));
- m_ourcpu->t1_in_cb().set(FUNC(usb_sound_device::t1_r));
-
- TIMER(config, "usb_timer", 0).configure_periodic(
- FUNC(usb_sound_device::increment_t1_clock_timer_cb),
- attotime::from_hz(USB_2MHZ_CLOCK / 256));
-}
-
-
-DEFINE_DEVICE_TYPE(SEGAUSBROM, usb_rom_sound_device, "segausbrom", "Sega Universal Sound Board with ROM")
-
-usb_rom_sound_device::usb_rom_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : usb_sound_device(mconfig, SEGAUSBROM, tag, owner, clock)
-{
-}
-
-void usb_sound_device::usb_map_rom(address_map &map)
-{
- map(0x0000, 0x0fff).rom().region(":usbcpu", 0);
-}
-
-void usb_rom_sound_device::device_add_mconfig(machine_config &config)
-{
- usb_sound_device::device_add_mconfig(config);
-
- /* CPU for the usb board */
- m_ourcpu->set_addrmap(AS_PROGRAM, &usb_rom_sound_device::usb_map_rom);
-}
diff --git a/src/mame/audio/segasnd.h b/src/mame/audio/segasnd.h
deleted file mode 100644
index 75fa94252bb..00000000000
--- a/src/mame/audio/segasnd.h
+++ /dev/null
@@ -1,214 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-/*************************************************************************
-
- Sega g80 common sound hardware
-
-*************************************************************************/
-#ifndef MAME_AUDIO_SEGASND_H
-#define MAME_AUDIO_SEGASND_H
-
-#pragma once
-
-#include "cpu/mcs48/mcs48.h"
-#include "machine/timer.h"
-
-class segag80snd_common : public driver_device {
-public:
- segag80snd_common(const machine_config &mconfig, device_type type, const char *tag) :
- driver_device(mconfig, type, tag),
- m_audiocpu(*this, "audiocpu")
- { }
-
- virtual ~segag80snd_common() = default;
-
- DECLARE_WRITE_LINE_MEMBER(segaspeech_int_w);
-
- void sega_speech_board(machine_config &config);
-
-protected:
- void speech_map(address_map &map);
- void speech_portmap(address_map &map);
-
- optional_device<cpu_device> m_audiocpu;
-};
-
-#define SEGASND_SEGASPEECH_REGION "segaspeech:speech"
-
-class speech_sound_device : public device_t, public device_sound_interface
-{
-public:
- speech_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
-
- auto int_cb() { return m_int_cb.bind(); }
-
- void data_w(uint8_t data);
- void control_w(uint8_t data);
-
- DECLARE_READ_LINE_MEMBER( t0_r );
- DECLARE_READ_LINE_MEMBER( t1_r );
- uint8_t p1_r();
- uint8_t rom_r(offs_t offset);
- void p1_w(uint8_t data);
- void p2_w(uint8_t data);
-
- DECLARE_WRITE_LINE_MEMBER(drq_w);
-
-protected:
- // device-level overrides
- virtual void device_start() override;
-
- // sound stream update overrides
- virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
-
-private:
- devcb_write_line m_int_cb;
- required_memory_region m_speech;
-
- // internal state
- u8 m_drq;
- u8 m_latch;
- u8 m_t0;
- u8 m_p2;
-
- TIMER_CALLBACK_MEMBER( delayed_speech_w );
-};
-
-DECLARE_DEVICE_TYPE(SEGASPEECH, speech_sound_device)
-
-class usb_sound_device : public device_t, public device_sound_interface
-{
-public:
- template <typename T> usb_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&maincpu_tag)
- : usb_sound_device(mconfig, tag, owner, clock)
- {
- m_maincpu.set_tag(maincpu_tag);
- }
-
- usb_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
-
- uint8_t status_r();
- void data_w(uint8_t data);
- uint8_t ram_r(offs_t offset);
- void ram_w(offs_t offset, uint8_t data);
-
- uint8_t workram_r(offs_t offset);
- void workram_w(offs_t offset, uint8_t data);
-
- TIMER_DEVICE_CALLBACK_MEMBER( increment_t1_clock_timer_cb );
-
- void usb_map(address_map &map);
- void usb_map_rom(address_map &map);
- void usb_portmap(address_map &map);
-
-protected:
- usb_sound_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
-
- // device-level overrides
- virtual void device_add_mconfig(machine_config &config) override;
- virtual void device_start() override;
- virtual void device_reset() override;
-
- // sound stream update overrides
- virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
-
- required_device<i8035_device> m_ourcpu;
- required_device<cpu_device> m_maincpu;
-
-private:
- struct g80_filter_state
- {
- g80_filter_state() { }
-
- void configure(double r, double c);
- double step_rc(double input);
- double step_cr(double input);
-
- double capval = 0.0; // current capacitor value
- double exponent = 0.0; // constant exponent
- };
-
-
- struct timer8253
- {
- struct channel
- {
- channel() { }
-
- void clock();
-
- u8 holding = 0; // holding until counts written? */
- u8 latchmode = 0; // latching mode */
- u8 latchtoggle = 0; // latching state */
- u8 clockmode = 0; // clocking mode */
- u8 bcdmode = 0; // BCD mode? */
- u8 output = 0; // current output value */
- u8 lastgate = 0; // previous gate value */
- u8 gate = 0; // current gate value */
- u8 subcount = 0; // subcount (2MHz clocks per input clock) */
- u16 count = 0; // initial count
- u16 remain = 0; // current down counter value
- };
-
- timer8253() : env{ 0.0, 0.0, 0.0 } { }
-
- channel chan[3]; // three channels' worth of information
- double env[3]; // envelope value for each channel
- g80_filter_state chan_filter[2]; // filter states for the first two channels
- g80_filter_state gate1; // first RC filter state
- g80_filter_state gate2; // second RC filter state
- u8 config = 0; // configuration for this timer
- };
-
- // internal state
- sound_stream *m_stream; // output stream
- u8 m_in_latch; // input latch
- u8 m_out_latch; // output latch
- u8 m_last_p2_value; // current P2 output value
- optional_shared_ptr<u8> m_program_ram; // pointer to program RAM
- required_shared_ptr<u8> m_work_ram; // pointer to work RAM
- u8 m_work_ram_bank; // currently selected work RAM bank
- u8 m_t1_clock; // T1 clock value
- u8 m_t1_clock_mask; // T1 clock mask (configured via jumpers)
- timer8253 m_timer_group[3]; // 3 groups of timers
- u8 m_timer_mode[3]; // mode control for each group
- u32 m_noise_shift;
- u8 m_noise_state;
- u8 m_noise_subcount;
- double m_gate_rc1_exp[2];
- double m_gate_rc2_exp[2];
- g80_filter_state m_final_filter;
- g80_filter_state m_noise_filters[5];
-
- TIMER_CALLBACK_MEMBER( delayed_usb_data_w );
- void timer_w(int which, u8 offset, u8 data);
- void env_w(int which, u8 offset, u8 data);
-
- uint8_t p1_r();
- void p1_w(uint8_t data);
- void p2_w(uint8_t data);
- DECLARE_READ_LINE_MEMBER( t1_r );
-};
-
-DECLARE_DEVICE_TYPE(SEGAUSB, usb_sound_device)
-
-
-class usb_rom_sound_device : public usb_sound_device
-{
-public:
- template <typename T> usb_rom_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&maincpu_tag)
- : usb_rom_sound_device(mconfig, tag, owner, clock)
- {
- m_maincpu.set_tag(maincpu_tag);
- }
-
- usb_rom_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
-
-protected:
- // device-level overrides
- virtual void device_add_mconfig(machine_config &config) override;
-};
-
-DECLARE_DEVICE_TYPE(SEGAUSBROM, usb_rom_sound_device)
-
-#endif // MAME_AUDIO_SEGASND_H
diff --git a/src/mame/audio/segaspeech.cpp b/src/mame/audio/segaspeech.cpp
new file mode 100644
index 00000000000..d158b0b7d2e
--- /dev/null
+++ b/src/mame/audio/segaspeech.cpp
@@ -0,0 +1,217 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ segaspeech.cpp
+
+ Sega Speech board for early G-80 games.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "segaspeech.h"
+
+#include "sound/sp0250.h"
+#include "includes/segag80r.h"
+#include "includes/segag80v.h"
+#include "audio/nl_segaspeech.h"
+
+#define VERBOSE 0
+#include "logmacro.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define SPEECH_MASTER_CLOCK 3120000
+
+
+
+/***************************************************************************
+ SPEECH BOARD
+***************************************************************************/
+
+DEFINE_DEVICE_TYPE(SEGA_SPEECH_BOARD, sega_speech_device, "sega_speech_device", "Sega Speech Sound Board")
+
+sega_speech_device::sega_speech_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, SEGA_SPEECH_BOARD, tag, owner, clock),
+ device_mixer_interface(mconfig, *this),
+ m_speech(*this, "data"),
+ m_cpu(*this, "cpu"),
+ m_drq(0),
+ m_latch(0),
+ m_t0(0),
+ m_p2(0)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void sega_speech_device::device_start()
+{
+ save_item(NAME(m_latch));
+ save_item(NAME(m_t0));
+ save_item(NAME(m_p2));
+ save_item(NAME(m_drq));
+}
+
+
+/*************************************
+ *
+ * i8035 port accessors
+ *
+ *************************************/
+
+READ_LINE_MEMBER( sega_speech_device::t0_r )
+{
+ return m_t0;
+}
+
+READ_LINE_MEMBER( sega_speech_device::t1_r )
+{
+//printf("%s: t1_r=%d\n", machine().scheduler().time().as_string(), m_drq);
+ return m_drq;
+}
+
+uint8_t sega_speech_device::p1_r()
+{
+ return m_latch & 0x7f;
+}
+
+uint8_t sega_speech_device::rom_r(offs_t offset)
+{
+ return m_speech->base()[0x100 * (m_p2 & 0x3f) + offset];
+}
+
+void sega_speech_device::p1_w(uint8_t data)
+{
+ if (!(data & 0x80))
+ m_t0 = 0;
+}
+
+void sega_speech_device::p2_w(uint8_t data)
+{
+ m_p2 = data;
+}
+
+
+
+/*************************************
+ *
+ * i8035 port accessors
+ *
+ *************************************/
+
+WRITE_LINE_MEMBER(sega_speech_device::drq_w)
+{
+//printf("%s: DRQ=%d\n", machine().scheduler().time().as_string(), state);
+ m_drq = (state == ASSERT_LINE);
+}
+
+
+
+/*************************************
+ *
+ * External access
+ *
+ *************************************/
+
+TIMER_CALLBACK_MEMBER( sega_speech_device::delayed_speech_w )
+{
+ int data = param;
+ u8 old = m_latch;
+
+ /* all 8 bits are latched */
+ m_latch = data;
+
+ /* the high bit goes directly to the INT line */
+ m_cpu->set_input_line(INPUT_LINE_IRQ0, (data & 0x80) ? CLEAR_LINE : ASSERT_LINE);
+
+ /* a clock on the high bit clocks a 1 into T0 */
+ if (!(old & 0x80) && (data & 0x80))
+ m_t0 = 1;
+}
+
+
+void sega_speech_device::data_w(uint8_t data)
+{
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(sega_speech_device::delayed_speech_w), this), data);
+}
+
+
+void sega_speech_device::control_w(uint8_t data)
+{
+ // bit 3 controls channel #1 of a CD4053 to enable/disable
+ // speech output
+ this->set_input_gain(0, BIT(data, 3) ? 1.0 : 0.0);
+
+ // bit 4 controls channel #2, but the source is unconnected
+
+ // bit 5 controls channel #3, which comes from off-board
+ // and has a pot to control the incoming volume; at least on
+ // Star Trek, this is the audio from the Universal Sound Board
+ this->set_input_gain(1, BIT(data, 5) ? 1.0 : 0.0);
+
+ LOG("Speech control = %X\n", data);
+}
+
+
+/*************************************
+ *
+ * Speech board address maps
+ *
+ *************************************/
+
+void sega_speech_device::speech_map(address_map &map)
+{
+ map(0x0000, 0x07ff).mirror(0x0800).rom();
+}
+
+
+void sega_speech_device::speech_portmap(address_map &map)
+{
+ map(0x00, 0xff).r(FUNC(sega_speech_device::rom_r));
+ map(0x00, 0xff).w("sp0250", FUNC(sp0250_device::write));
+}
+
+
+/*************************************
+ *
+ * Speech board machine drivers
+ *
+ *************************************/
+
+void sega_speech_device::device_add_mconfig(machine_config &config)
+{
+ // CPU for the speech board
+ i8035_device &audiocpu(I8035(config, "cpu", SPEECH_MASTER_CLOCK)); // divide by 15 in CPU
+ audiocpu.set_addrmap(AS_PROGRAM, &sega_speech_device::speech_map);
+ audiocpu.set_addrmap(AS_IO, &sega_speech_device::speech_portmap);
+ audiocpu.p1_in_cb().set(FUNC(sega_speech_device::p1_r));
+ audiocpu.p1_out_cb().set(FUNC(sega_speech_device::p1_w));
+ audiocpu.p2_out_cb().set(FUNC(sega_speech_device::p2_w));
+ audiocpu.t0_in_cb().set(FUNC(sega_speech_device::t0_r));
+ audiocpu.t1_in_cb().set(FUNC(sega_speech_device::t1_r));
+
+ // speech chip
+ sp0250_device &speech(SP0250(config, "sp0250", SPEECH_MASTER_CLOCK));
+ speech.drq().set(FUNC(sega_speech_device::drq_w));
+#if (ENABLE_NETLIST_FILTERING)
+ speech.set_pwm_mode();
+ speech.add_route(ALL_OUTPUTS, "sound_nl", 1.0, 0);
+
+ // netlist filtering
+ NETLIST_SOUND(config, "sound_nl", SPEECH_MASTER_CLOCK/2)
+ .set_source(NETLIST_NAME(segaspeech))
+ .add_route(ALL_OUTPUTS, *this, 1.0);
+
+ NETLIST_STREAM_INPUT(config, "sound_nl:cin0", 0, "I_SP0250.IN").set_mult_offset(1.0 / 32767.0, 0);
+
+ NETLIST_STREAM_OUTPUT(config, "sound_nl:cout0", 0, "OUTPUT").set_mult_offset(75000.0, 0.0);
+#else
+ speech.add_route(ALL_OUTPUTS, *this, 1.0);
+#endif
+}
diff --git a/src/mame/audio/segaspeech.h b/src/mame/audio/segaspeech.h
new file mode 100644
index 00000000000..a9905ce05f5
--- /dev/null
+++ b/src/mame/audio/segaspeech.h
@@ -0,0 +1,61 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/*************************************************************************
+
+ Sega speech board
+
+*************************************************************************/
+#ifndef MAME_AUDIO_SEGASPEECH_H
+#define MAME_AUDIO_SEGASPEECH_H
+
+#pragma once
+
+#define ENABLE_NETLIST_FILTERING (0)
+
+#include "cpu/mcs48/mcs48.h"
+#include "machine/netlist.h"
+#include "machine/timer.h"
+
+class sega_speech_device : public device_t, public device_mixer_interface
+{
+public:
+ sega_speech_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+// auto int_cb() { return m_int_cb.bind(); }
+
+ void data_w(uint8_t data);
+ void control_w(uint8_t data);
+
+protected:
+ // device-level overrides
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_start() override;
+
+ DECLARE_READ_LINE_MEMBER( t0_r );
+ DECLARE_READ_LINE_MEMBER( t1_r );
+ uint8_t p1_r();
+ uint8_t rom_r(offs_t offset);
+ void p1_w(uint8_t data);
+ void p2_w(uint8_t data);
+
+ DECLARE_WRITE_LINE_MEMBER(drq_w);
+
+private:
+ void speech_map(address_map &map);
+ void speech_portmap(address_map &map);
+
+ required_memory_region m_speech;
+ required_device<cpu_device> m_cpu;
+
+ // internal state
+ u8 m_drq;
+ u8 m_latch;
+ u8 m_t0;
+ u8 m_p2;
+
+ TIMER_CALLBACK_MEMBER( delayed_speech_w );
+};
+
+DECLARE_DEVICE_TYPE(SEGA_SPEECH_BOARD, sega_speech_device)
+
+#endif // MAME_AUDIO_SEGASPEECH_H
diff --git a/src/mame/audio/segausb.cpp b/src/mame/audio/segausb.cpp
new file mode 100644
index 00000000000..59e1c226854
--- /dev/null
+++ b/src/mame/audio/segausb.cpp
@@ -0,0 +1,859 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ segausb.cpp
+
+ Sega Universal Sound Board.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "segausb.h"
+#include "nl_segausb.h"
+
+#include "includes/segag80r.h"
+#include "includes/segag80v.h"
+
+#include <cmath>
+
+
+#define VERBOSE 0
+#include "logmacro.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define USB_MASTER_CLOCK 6000000
+#define USB_2MHZ_CLOCK (USB_MASTER_CLOCK/3)
+#define USB_PCS_CLOCK (USB_2MHZ_CLOCK/2)
+#define USB_GOS_CLOCK (USB_2MHZ_CLOCK/16/4)
+#define MM5837_CLOCK 100000
+
+
+/***************************************************************************
+ UNIVERSAL SOUND BOARD
+***************************************************************************/
+
+DEFINE_DEVICE_TYPE(SEGAUSB, usb_sound_device, "segausb", "Sega Universal Sound Board")
+
+usb_sound_device::usb_sound_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, type, tag, owner, clock),
+ device_mixer_interface(mconfig, *this),
+ m_in_latch(0),
+ m_out_latch(0),
+ m_last_p2_value(0),
+ m_program_ram(*this, "pgmram"),
+ m_work_ram(*this, "workram"),
+ m_work_ram_bank(0),
+ m_t1_clock(0),
+ m_t1_clock_mask(0),
+ m_ourcpu(*this, "ourcpu"),
+ m_maincpu(*this, finder_base::DUMMY_TAG),
+#if (ENABLE_SEGAUSB_NETLIST)
+ m_pit(*this, "pit_%u", 0),
+ m_nl_dac0(*this, "sound_nl:dac0_%u", 0),
+ m_nl_sel0(*this, "sound_nl:sel0"),
+ m_nl_pit0_out(*this, "sound_nl:pit0_out%u", 0),
+ m_nl_dac1(*this, "sound_nl:dac1_%u", 0),
+ m_nl_sel1(*this, "sound_nl:sel1"),
+ m_nl_pit1_out(*this, "sound_nl:pit1_out%u", 0),
+ m_nl_dac2(*this, "sound_nl:dac2_%u", 0),
+ m_nl_sel2(*this, "sound_nl:sel2"),
+ m_nl_pit2_out(*this, "sound_nl:pit2_out%u", 0),
+ m_gos_clock(0)
+#else
+ m_stream(nullptr),
+ m_noise_shift(0),
+ m_noise_state(0),
+ m_noise_subcount(0)
+#endif
+{
+}
+
+usb_sound_device::usb_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : usb_sound_device(mconfig, SEGAUSB, tag, owner, clock)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void usb_sound_device::device_start()
+{
+ // register for save states
+ save_item(NAME(m_in_latch));
+ save_item(NAME(m_out_latch));
+ save_item(NAME(m_last_p2_value));
+ save_item(NAME(m_work_ram_bank));
+ save_item(NAME(m_t1_clock));
+
+#if (ENABLE_SEGAUSB_NETLIST)
+
+ for (int index = 0; index < 3; index++)
+ {
+ m_pit[index]->write_gate0(1);
+ m_pit[index]->write_gate1(1);
+ m_pit[index]->write_gate2(1);
+ }
+ save_item(NAME(m_gos_clock));
+
+#else
+
+ m_stream = stream_alloc(0, 1, USB_2MHZ_CLOCK);
+
+ m_noise_shift = 0x15555;
+
+ for (timer8253 &group : m_timer_group)
+ {
+ group.chan_filter[0].configure(10e3, 1e-6);
+ group.chan_filter[1].configure(10e3, 1e-6);
+ group.gate1.configure(100e3, 0.01e-6);
+ group.gate2.configure(2 * 100e3, 0.01e-6);
+ }
+
+ g80_filter_state temp;
+ temp.configure(100e3, 0.01e-6);
+ m_gate_rc1_exp[0] = temp.exponent;
+ temp.configure(1e3, 0.01e-6);
+ m_gate_rc1_exp[1] = temp.exponent;
+ temp.configure(2 * 100e3, 0.01e-6);
+ m_gate_rc2_exp[0] = temp.exponent;
+ temp.configure(2 * 1e3, 0.01e-6);
+ m_gate_rc2_exp[1] = temp.exponent;
+
+ m_noise_filters[0].configure(2.7e3 + 2.7e3, 1.0e-6);
+ m_noise_filters[1].configure(2.7e3 + 1e3, 0.30e-6);
+ m_noise_filters[2].configure(2.7e3 + 270, 0.15e-6);
+ m_noise_filters[3].configure(2.7e3 + 0, 0.082e-6);
+ m_noise_filters[4].configure(33e3, 0.1e-6);
+
+ m_final_filter.configure(100e3, 4.7e-6);
+
+ for (int tgroup = 0; tgroup < 3; tgroup++)
+ {
+ timer8253 &group = m_timer_group[tgroup];
+ for (int tchan = 0; tchan < 3; tchan++)
+ {
+ timer8253::channel &channel = group.chan[tchan];
+ save_item(NAME(channel.holding), tgroup * 3 + tchan);
+ save_item(NAME(channel.latchmode), tgroup * 3 + tchan);
+ save_item(NAME(channel.latchtoggle), tgroup * 3 + tchan);
+ save_item(NAME(channel.clockmode), tgroup * 3 + tchan);
+ save_item(NAME(channel.bcdmode), tgroup * 3 + tchan);
+ save_item(NAME(channel.output), tgroup * 3 + tchan);
+ save_item(NAME(channel.lastgate), tgroup * 3 + tchan);
+ save_item(NAME(channel.gate), tgroup * 3 + tchan);
+ save_item(NAME(channel.subcount), tgroup * 3 + tchan);
+ save_item(NAME(channel.count), tgroup * 3 + tchan);
+ save_item(NAME(channel.remain), tgroup * 3 + tchan);
+ }
+ save_item(NAME(group.env), tgroup);
+ save_item(NAME(group.chan_filter[0].capval), tgroup);
+ save_item(NAME(group.chan_filter[1].capval), tgroup);
+ save_item(NAME(group.gate1.capval), tgroup);
+ save_item(NAME(group.gate2.capval), tgroup);
+ save_item(NAME(group.config), tgroup);
+ }
+
+ save_item(NAME(m_timer_mode));
+ save_item(NAME(m_noise_shift));
+ save_item(NAME(m_noise_state));
+ save_item(NAME(m_noise_subcount));
+ save_item(NAME(m_final_filter.capval));
+ save_item(NAME(m_noise_filters[0].capval));
+ save_item(NAME(m_noise_filters[1].capval));
+ save_item(NAME(m_noise_filters[2].capval));
+ save_item(NAME(m_noise_filters[3].capval));
+ save_item(NAME(m_noise_filters[4].capval));
+
+#endif
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void usb_sound_device::device_reset()
+{
+ // halt the USB CPU at reset time
+ m_ourcpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
+
+ // start the clock timer
+ m_t1_clock_mask = 0x10;
+}
+
+
+/*************************************
+ *
+ * Initialization/reset
+ *
+ *************************************/
+
+TIMER_DEVICE_CALLBACK_MEMBER( usb_sound_device::increment_t1_clock_timer_cb )
+{
+ // only increment if it is not being forced clear
+ if (!(m_last_p2_value & 0x80))
+ m_t1_clock++;
+}
+
+
+/*************************************
+ *
+ * External access
+ *
+ *************************************/
+
+u8 usb_sound_device::status_r()
+{
+ LOG("%s:usb_data_r = %02X\n", machine().describe_context(), (m_out_latch & 0x81) | (m_in_latch & 0x7e));
+
+ m_maincpu->adjust_icount(-200);
+
+ // only bits 0 and 7 are controlled by the I8035; the remaining
+ // bits 1-6 reflect the current input latch values
+ return (m_out_latch & 0x81) | (m_in_latch & 0x7e);
+}
+
+
+TIMER_CALLBACK_MEMBER( usb_sound_device::delayed_usb_data_w )
+{
+ // look for rising/falling edges of bit 7 to control the RESET line
+ int data = param;
+ m_ourcpu->set_input_line(INPUT_LINE_RESET, (data & 0x80) ? ASSERT_LINE : CLEAR_LINE);
+
+ // if the CLEAR line is set, the low 7 bits of the input are ignored
+ if ((m_last_p2_value & 0x40) == 0)
+ data &= ~0x7f;
+
+ // update the effective input latch
+ m_in_latch = data;
+}
+
+
+void usb_sound_device::data_w(u8 data)
+{
+ LOG("%s:usb_data_w = %02X\n", machine().describe_context(), data);
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(usb_sound_device::delayed_usb_data_w), this), data);
+
+ // boost the interleave so that sequences can be sent
+ machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(250));
+}
+
+
+u8 usb_sound_device::ram_r(offs_t offset)
+{
+ return m_program_ram[offset];
+}
+
+
+void usb_sound_device::ram_w(offs_t offset, u8 data)
+{
+ if (m_in_latch & 0x80)
+ m_program_ram[offset] = data;
+ else
+ LOG("%s:sega_usb_ram_w(%03X) = %02X while /LOAD disabled\n", machine().describe_context(), offset, data);
+}
+
+
+
+/*************************************
+ *
+ * I8035 port accesses
+ *
+ *************************************/
+
+u8 usb_sound_device::p1_r()
+{
+ // bits 0-6 are inputs and map to bits 0-6 of the input latch
+ if ((m_in_latch & 0x7f) != 0)
+ LOG("%s: P1 read = %02X\n", machine().describe_context(), m_in_latch & 0x7f);
+ return m_in_latch & 0x7f;
+}
+
+
+void usb_sound_device::p1_w(u8 data)
+{
+ // bit 7 maps to bit 0 on the output latch
+ m_out_latch = (m_out_latch & 0xfe) | (data >> 7);
+ LOG("%s: P1 write = %02X\n", machine().describe_context(), data);
+}
+
+
+void usb_sound_device::p2_w(u8 data)
+{
+ u8 old = m_last_p2_value;
+ m_last_p2_value = data;
+
+ // low 2 bits control the bank of work RAM we are addressing
+ m_work_ram_bank = data & 3;
+
+ // bit 6 controls the "ready" bit output to the host
+ // it also clears the input latch from the host (active low)
+ m_out_latch = ((data & 0x40) << 1) | (m_out_latch & 0x7f);
+ if ((data & 0x40) == 0)
+ m_in_latch = 0;
+
+ // bit 7 controls the reset on the upper counter at U33
+ if ((old & 0x80) && !(data & 0x80))
+ m_t1_clock = 0;
+
+ LOG("%s: P2 write -> bank=%d ready=%d clock=%d\n", machine().describe_context(), data & 3, (data >> 6) & 1, (data >> 7) & 1);
+}
+
+
+READ_LINE_MEMBER( usb_sound_device::t1_r )
+{
+ // T1 returns 1 based on the value of the T1 clock; the exact
+ // pattern is determined by one or more jumpers on the board.
+ return (m_t1_clock & m_t1_clock_mask) != 0;
+}
+
+
+
+/*************************************
+ *
+ * Sound generation
+ *
+ *************************************/
+
+#if (!ENABLE_SEGAUSB_NETLIST)
+
+inline void usb_sound_device::g80_filter_state::configure(double r, double c)
+{
+ capval = 0.0;
+ exponent = 1.0 - std::exp(-1.0 / (r * c * USB_2MHZ_CLOCK));
+}
+
+inline void usb_sound_device::timer8253::channel::clock()
+{
+ u8 const old_lastgate = lastgate;
+
+ // update the gate
+ lastgate = gate;
+
+ // if we're holding, skip
+ if (holding)
+ return;
+
+ // switch off the clock mode
+ switch (clockmode)
+ {
+ // oneshot; waits for trigger to restart
+ case 1:
+ if (!old_lastgate && gate)
+ {
+ output = 0;
+ remain = count;
+ }
+ else
+ {
+ if (--remain == 0)
+ output = 1;
+ }
+ break;
+
+ // square wave: counts down by 2 and toggles output
+ case 3:
+ remain = (remain - 1) & ~1;
+ if (remain == 0)
+ {
+ output ^= 1;
+ remain = count;
+ }
+ break;
+ }
+}
+
+
+/*************************************
+ *
+ * USB timer and envelope controls
+ *
+ *************************************/
+
+void usb_sound_device::timer_w(int which, u8 offset, u8 data)
+{
+ timer8253 &group = m_timer_group[which];
+
+ m_stream->update();
+
+ // switch off the offset
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ case 2:
+ {
+ timer8253::channel &ch = group.chan[offset];
+ bool was_holding = ch.holding;
+
+ // based on the latching mode
+ switch (ch.latchmode)
+ {
+ case 1: // low word only
+ ch.count = data;
+ ch.holding = false;
+ break;
+
+ case 2: // high word only
+ ch.count = data << 8;
+ ch.holding = false;
+ break;
+
+ case 3: // low word followed by high word
+ if (ch.latchtoggle == 0)
+ {
+ ch.count = (ch.count & 0xff00) | (data & 0x00ff);
+ ch.latchtoggle = 1;
+ }
+ else
+ {
+ ch.count = (ch.count & 0x00ff) | (data << 8);
+ ch.holding = false;
+ ch.latchtoggle = 0;
+ }
+ break;
+ }
+
+ // if we're not holding, load the initial count for some modes
+ if (was_holding && !ch.holding)
+ ch.remain = 1;
+ break;
+ }
+
+ case 3:
+ // break out the components
+ if (((data & 0xc0) >> 6) < 3)
+ {
+ timer8253::channel &ch = group.chan[(data & 0xc0) >> 6];
+
+ // extract the bits
+ ch.holding = true;
+ ch.latchmode = (data >> 4) & 3;
+ ch.clockmode = (data >> 1) & 7;
+ ch.bcdmode = (data >> 0) & 1;
+ ch.latchtoggle = 0;
+ ch.output = (ch.clockmode == 1);
+ }
+ break;
+ }
+}
+
+
+void usb_sound_device::env_w(int which, u8 offset, u8 data)
+{
+ timer8253 &group = m_timer_group[which];
+
+ m_stream->update();
+
+ if (offset < 3)
+ group.env[offset] = double(data);
+ else
+ group.config = data & 1;
+}
+
+//-------------------------------------------------
+// sound_stream_update - handle a stream update
+//-------------------------------------------------
+
+void usb_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+{
+ stream_sample_t *dest = outputs[0];
+
+ // iterate over samples
+ while (samples--)
+ {
+ /*----------------
+ Noise Source
+ ----------------
+
+ RC
+ MM5837 ---> FILTER ---> CR FILTER ---> 3.2x AMP ---> NOISE
+ LADDER
+ */
+
+ // update the noise source
+ if (m_noise_subcount-- == 0)
+ {
+ m_noise_shift = (m_noise_shift << 1) | (((m_noise_shift >> 13) ^ (m_noise_shift >> 16)) & 1);
+ m_noise_state = (m_noise_shift >> 16) & 1;
+ m_noise_subcount += USB_2MHZ_CLOCK / MM5837_CLOCK;
+ }
+
+ // update the filtered noise value -- this is just an approximation to the pink noise filter
+ // being applied on the PCB, but it sounds pretty close
+ m_noise_filters[0].capval = 0.99765 * m_noise_filters[0].capval + m_noise_state * 0.0990460;
+ m_noise_filters[1].capval = 0.96300 * m_noise_filters[1].capval + m_noise_state * 0.2965164;
+ m_noise_filters[2].capval = 0.57000 * m_noise_filters[2].capval + m_noise_state * 1.0526913;
+ double noiseval = m_noise_filters[0].capval + m_noise_filters[1].capval + m_noise_filters[2].capval + m_noise_state * 0.1848;
+
+ // final output goes through a CR filter; the scaling factor is arbitrary to get the noise to the
+ // correct relative volume
+ noiseval = m_noise_filters[4].step_cr(noiseval);
+ noiseval *= 0.075;
+
+ // there are 3 identical groups of circuits, each with its own 8253
+ double sample = 0;
+ for (int groupnum = 0; groupnum < 3; groupnum++)
+ {
+ timer8253 &group = m_timer_group[groupnum];
+
+ /*-------------
+ Channel 0
+ -------------
+
+ 8253 CR AD7524
+ OUT0 ---> FILTER ---> BUFFER---> VRef ---> 100k ---> mix
+ */
+
+ // channel 0 clocks with the PCS clock
+ if (group.chan[0].subcount-- == 0)
+ {
+ group.chan[0].subcount += USB_2MHZ_CLOCK / USB_PCS_CLOCK;
+ group.chan[0].gate = 1;
+ group.chan[0].clock();
+ }
+
+ // channel 0 is mixed in with a resistance of 100k
+ double chan0 = group.chan_filter[0].step_cr(group.chan[0].output) * group.env[0] * (1.0/100.0);
+
+ /*-------------
+ Channel 1
+ -------------
+
+ 8253 CR AD7524
+ OUT1 ---> FILTER ---> BUFFER---> VRef ---> 100k ---> mix
+ */
+
+ // channel 1 clocks with the PCS clock
+ if (group.chan[1].subcount-- == 0)
+ {
+ group.chan[1].subcount += USB_2MHZ_CLOCK / USB_PCS_CLOCK;
+ group.chan[1].gate = 1;
+ group.chan[1].clock();
+ }
+
+ // channel 1 is mixed in with a resistance of 100k
+ double chan1 = group.chan_filter[1].step_cr(group.chan[1].output) * group.env[1] * (1.0/100.0);
+
+ /*-------------
+ Channel 2
+ -------------
+
+ If timer_mode == 0:
+
+ SWITCHED AD7524
+ NOISE ---> RC ---> 1.56x AMP ---> INVERTER ---> VRef ---> 33k ---> mix
+ FILTERS
+
+ If timer mode == 1:
+
+ AD7524 SWITCHED
+ NOISE ---> INVERTER ---> VRef ---> 33k ---> mix ---> INVERTER ---> RC ---> 1.56x AMP ---> finalmix
+ FILTERS
+ */
+
+ // channel 2 clocks with the 2MHZ clock and triggers with the GOS clock
+ if (group.chan[2].subcount-- == 0)
+ {
+ group.chan[2].subcount += USB_2MHZ_CLOCK / USB_GOS_CLOCK / 2;
+ group.chan[2].gate = !group.chan[2].gate;
+ }
+ group.chan[2].clock();
+
+ // the exponents for the gate filters are determined by channel 2's output
+ group.gate1.exponent = m_gate_rc1_exp[group.chan[2].output];
+ group.gate2.exponent = m_gate_rc2_exp[group.chan[2].output];
+
+ // based on the envelope mode, we do one of two things with source 2
+ double chan2, mix;
+ if (group.config == 0)
+ {
+ chan2 = group.gate2.step_rc(group.gate1.step_rc(noiseval)) * -1.56 * group.env[2] * (1.0/33.0);
+ mix = chan0 + chan1 + chan2;
+ }
+ else
+ {
+ chan2 = -noiseval * group.env[2] * (1.0/33.0);
+ mix = chan0 + chan1 + chan2;
+ mix = group.gate2.step_rc(group.gate1.step_rc(-mix)) * 1.56;
+ }
+
+ // accumulate the sample
+ sample += mix;
+ }
+
+ /*-------------
+ Final mix
+ -------------
+
+ INPUTS
+ EQUAL ---> 1.2x INVERTER ---> CR FILTER ---> out
+ WEIGHT
+
+ */
+ *dest++ = 3000 * m_final_filter.step_cr(sample);
+ }
+}
+
+#endif
+
+
+
+/*************************************
+ *
+ * USB work RAM access
+ *
+ *************************************/
+
+u8 usb_sound_device::workram_r(offs_t offset)
+{
+ offset += 256 * m_work_ram_bank;
+ return m_work_ram[offset];
+}
+
+
+void usb_sound_device::workram_w(offs_t offset, u8 data)
+{
+ offset += 256 * m_work_ram_bank;
+ m_work_ram[offset] = data;
+
+ // writes to the low 32 bytes go to various controls
+#if (ENABLE_SEGAUSB_NETLIST)
+
+ switch (offset)
+ {
+ case 0x00: // 8253 U41
+ case 0x01: // 8253 U41
+ case 0x02: // 8253 U41
+ case 0x03: // 8253 U41
+ if ((offset & 3) != 3)
+ printf("%s: 2.%d count=%d\n", machine().scheduler().time().as_string(), offset & 3, data);
+ m_pit[0]->write(offset & 3, data);
+ break;
+
+ case 0x04: // ENV0 U26
+ case 0x05: // ENV0 U25
+ case 0x06: // ENV0 U24
+ m_nl_dac0[offset & 3]->write(double(data) / 255.0);
+ break;
+
+ case 0x07: // ENV0 U38B
+ m_nl_sel0->write(data & 1);
+ break;
+
+ case 0x08: // 8253 U42
+ case 0x09: // 8253 U42
+ case 0x0a: // 8253 U42
+ case 0x0b: // 8253 U42
+ if ((offset & 3) != 3)
+ printf("%s: 2.%d count=%d\n", machine().scheduler().time().as_string(), offset & 3, data);
+ m_pit[1]->write(offset & 3, data);
+ break;
+
+ case 0x0c: // ENV1 U12
+ case 0x0d: // ENV1 U13
+ case 0x0e: // ENV1 U14
+ m_nl_dac1[offset & 3]->write(double(data) / 255.0);
+ break;
+
+ case 0x0f: // ENV1 U2B
+ m_nl_sel1->write(data & 1);
+ break;
+
+ case 0x10: // 8253 U43
+ case 0x11: // 8253 U43
+ case 0x12: // 8253 U43
+ case 0x13: // 8253 U43
+ if ((offset & 3) != 3)
+ printf("%s: 2.%d count=%d\n", machine().scheduler().time().as_string(), offset & 3, data);
+ m_pit[2]->write(offset & 3, data);
+ break;
+
+ case 0x14: // ENV2 U27
+ case 0x15: // ENV2 U28
+ case 0x16: // ENV2 U29
+ m_nl_dac2[offset & 3]->write(double(data) / 255.0);
+ break;
+
+ case 0x17: // ENV2 U38B
+ m_nl_sel2->write(data & 1);
+ break;
+ }
+
+#else
+
+ switch (offset & ~3)
+ {
+ case 0x00: // CTC0
+ timer_w(0, offset & 3, data);
+ break;
+
+ case 0x04: // ENV0
+ env_w(0, offset & 3, data);
+ break;
+
+ case 0x08: // CTC1
+ timer_w(1, offset & 3, data);
+ break;
+
+ case 0x0c: // ENV1
+ env_w(1, offset & 3, data);
+ break;
+
+ case 0x10: // CTC2
+ timer_w(2, offset & 3, data);
+ break;
+
+ case 0x14: // ENV2
+ env_w(2, offset & 3, data);
+ break;
+ }
+
+#endif
+}
+
+
+
+/*************************************
+ *
+ * USB address maps
+ *
+ *************************************/
+
+void usb_sound_device::usb_map(address_map &map)
+{
+ map(0x0000, 0x0fff).ram().share("pgmram");
+}
+
+void usb_sound_device::usb_portmap(address_map &map)
+{
+ map(0x00, 0xff).rw(FUNC(usb_sound_device::workram_r), FUNC(usb_sound_device::workram_w)).share("workram");
+}
+
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+#if (ENABLE_SEGAUSB_NETLIST)
+
+TIMER_DEVICE_CALLBACK_MEMBER( usb_sound_device::gos_timer )
+{
+ // technically we should clock at 2x and toggle between states
+ // however, in practice this is just used to trigger a oneshot
+ // so we can halve the high frequency rate and just toggle both
+ // ways to initiate the countdown
+ m_pit[0]->write_gate2(0);
+ m_pit[1]->write_gate2(0);
+ m_pit[2]->write_gate2(0);
+ m_pit[0]->write_gate2(1);
+ m_pit[1]->write_gate2(1);
+ m_pit[2]->write_gate2(1);
+}
+
+#endif
+
+
+void usb_sound_device::device_add_mconfig(machine_config &config)
+{
+ // CPU for the usb board
+ I8035(config, m_ourcpu, USB_MASTER_CLOCK); // divide by 15 in CPU
+ m_ourcpu->set_addrmap(AS_PROGRAM, &usb_sound_device::usb_map);
+ m_ourcpu->set_addrmap(AS_IO, &usb_sound_device::usb_portmap);
+ m_ourcpu->p1_in_cb().set(FUNC(usb_sound_device::p1_r));
+ m_ourcpu->p1_out_cb().set(FUNC(usb_sound_device::p1_w));
+ m_ourcpu->p2_out_cb().set(FUNC(usb_sound_device::p2_w));
+ m_ourcpu->t1_in_cb().set(FUNC(usb_sound_device::t1_r));
+
+ TIMER(config, "usb_timer", 0).configure_periodic(
+ FUNC(usb_sound_device::increment_t1_clock_timer_cb),
+ attotime::from_hz(USB_2MHZ_CLOCK / 256));
+
+#if (ENABLE_SEGAUSB_NETLIST)
+
+ TIMER(config, "gos_timer", 0).configure_periodic(
+ FUNC(usb_sound_device::gos_timer), attotime::from_hz(USB_GOS_CLOCK));
+
+ NETLIST_SOUND(config, "sound_nl", 48000)
+ .set_source(NETLIST_NAME(segausb))
+ .add_route(ALL_OUTPUTS, *this, 1.0);
+
+ // channel 0 inputs
+ NETLIST_ANALOG_INPUT(config, m_nl_dac0[0], "I_U26_DAC.IN");
+ NETLIST_ANALOG_INPUT(config, m_nl_dac0[1], "I_U25_DAC.IN");
+ NETLIST_ANALOG_INPUT(config, m_nl_dac0[2], "I_U24_DAC.IN");
+ NETLIST_LOGIC_INPUT(config, m_nl_sel0, "I_U38B_SEL.IN", 0);
+ NETLIST_LOGIC_INPUT(config, m_nl_pit0_out[0], "I_U41_OUT0.IN", 0);
+ NETLIST_LOGIC_INPUT(config, m_nl_pit0_out[1], "I_U41_OUT1.IN", 0);
+ NETLIST_LOGIC_INPUT(config, m_nl_pit0_out[2], "I_U41_OUT2.IN", 0);
+
+ // channel 1 inputs
+ NETLIST_ANALOG_INPUT(config, m_nl_dac1[0], "I_U12_DAC.IN");
+ NETLIST_ANALOG_INPUT(config, m_nl_dac1[1], "I_U13_DAC.IN");
+ NETLIST_ANALOG_INPUT(config, m_nl_dac1[2], "I_U14_DAC.IN");
+ NETLIST_LOGIC_INPUT(config, m_nl_sel1, "I_U2B_SEL.IN", 0);
+ NETLIST_LOGIC_INPUT(config, m_nl_pit1_out[0], "I_U42_OUT0.IN", 0);
+ NETLIST_LOGIC_INPUT(config, m_nl_pit1_out[1], "I_U42_OUT1.IN", 0);
+ NETLIST_LOGIC_INPUT(config, m_nl_pit1_out[2], "I_U42_OUT2.IN", 0);
+
+ // channel 2 inputs
+ NETLIST_ANALOG_INPUT(config, m_nl_dac2[0], "I_U27_DAC.IN");
+ NETLIST_ANALOG_INPUT(config, m_nl_dac2[1], "I_U28_DAC.IN");
+ NETLIST_ANALOG_INPUT(config, m_nl_dac2[2], "I_U29_DAC.IN");
+ NETLIST_LOGIC_INPUT(config, m_nl_sel2, "I_U2A_SEL.IN", 0);
+ NETLIST_LOGIC_INPUT(config, m_nl_pit2_out[0], "I_U43_OUT0.IN", 0);
+ NETLIST_LOGIC_INPUT(config, m_nl_pit2_out[1], "I_U43_OUT1.IN", 0);
+ NETLIST_LOGIC_INPUT(config, m_nl_pit2_out[2], "I_U43_OUT2.IN", 0);
+
+ // final output
+ NETLIST_STREAM_OUTPUT(config, "sound_nl:cout0", 0, "OUTPUT").set_mult_offset(5000.0, 0.0);
+
+ // configure the PIT clocks and gates
+ for (int index = 0; index < 3; index++)
+ {
+ PIT8253(config, m_pit[index], 0);
+ m_pit[index]->set_clk<0>(USB_PCS_CLOCK);
+ m_pit[index]->set_clk<1>(USB_PCS_CLOCK);
+ m_pit[index]->set_clk<2>(USB_2MHZ_CLOCK);
+ }
+
+ // connect the PIT outputs to the netlist
+ m_pit[0]->out_handler<0>().set(m_nl_pit0_out[0], FUNC(netlist_mame_logic_input_device::write_line));
+ m_pit[0]->out_handler<1>().set(m_nl_pit0_out[1], FUNC(netlist_mame_logic_input_device::write_line));
+ m_pit[0]->out_handler<2>().set(m_nl_pit0_out[2], FUNC(netlist_mame_logic_input_device::write_line));
+ m_pit[1]->out_handler<0>().set(m_nl_pit1_out[0], FUNC(netlist_mame_logic_input_device::write_line));
+ m_pit[1]->out_handler<1>().set(m_nl_pit1_out[1], FUNC(netlist_mame_logic_input_device::write_line));
+ m_pit[1]->out_handler<2>().set(m_nl_pit1_out[2], FUNC(netlist_mame_logic_input_device::write_line));
+ m_pit[2]->out_handler<0>().set(m_nl_pit2_out[0], FUNC(netlist_mame_logic_input_device::write_line));
+ m_pit[2]->out_handler<1>().set(m_nl_pit2_out[1], FUNC(netlist_mame_logic_input_device::write_line));
+ m_pit[2]->out_handler<2>().set(m_nl_pit2_out[2], FUNC(netlist_mame_logic_input_device::write_line));
+
+#endif
+}
+
+
+DEFINE_DEVICE_TYPE(SEGAUSBROM, usb_rom_sound_device, "segausbrom", "Sega Universal Sound Board with ROM")
+
+usb_rom_sound_device::usb_rom_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : usb_sound_device(mconfig, SEGAUSBROM, tag, owner, clock)
+{
+}
+
+void usb_sound_device::usb_map_rom(address_map &map)
+{
+ map(0x0000, 0x0fff).rom().region(":usbcpu", 0);
+}
+
+void usb_rom_sound_device::device_add_mconfig(machine_config &config)
+{
+ usb_sound_device::device_add_mconfig(config);
+
+ // CPU for the usb board
+ m_ourcpu->set_addrmap(AS_PROGRAM, &usb_rom_sound_device::usb_map_rom);
+}
diff --git a/src/mame/audio/segausb.h b/src/mame/audio/segausb.h
new file mode 100644
index 00000000000..afed3b688af
--- /dev/null
+++ b/src/mame/audio/segausb.h
@@ -0,0 +1,192 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/*************************************************************************
+
+ Sega g80 common sound hardware
+
+*************************************************************************/
+#ifndef MAME_AUDIO_SEGAUSB_H
+#define MAME_AUDIO_SEGAUSB_H
+
+#pragma once
+
+#define ENABLE_SEGAUSB_NETLIST (0)
+
+#include "cpu/mcs48/mcs48.h"
+#include "machine/netlist.h"
+#include "machine/timer.h"
+#include "netlist/nl_setup.h"
+#include "nl_segausb.h"
+
+#if (ENABLE_SEGAUSB_NETLIST)
+#include "machine/pit8253.h"
+#endif
+
+class usb_sound_device : public device_t, public device_mixer_interface
+{
+public:
+ template <typename T> usb_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&maincpu_tag)
+ : usb_sound_device(mconfig, tag, owner, clock)
+ {
+ m_maincpu.set_tag(maincpu_tag);
+ }
+
+ usb_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ uint8_t status_r();
+ void data_w(uint8_t data);
+ uint8_t ram_r(offs_t offset);
+ void ram_w(offs_t offset, uint8_t data);
+
+ uint8_t workram_r(offs_t offset);
+ void workram_w(offs_t offset, uint8_t data);
+
+ TIMER_DEVICE_CALLBACK_MEMBER( increment_t1_clock_timer_cb );
+
+ void usb_map(address_map &map);
+ void usb_map_rom(address_map &map);
+ void usb_portmap(address_map &map);
+
+#if (ENABLE_SEGAUSB_NETLIST)
+ TIMER_DEVICE_CALLBACK_MEMBER( gos_timer );
+#endif
+
+protected:
+
+ usb_sound_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
+
+ // device-level overrides
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+#if (!ENABLE_SEGAUSB_NETLIST)
+ // sound stream update overrides
+ virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
+#endif
+
+private:
+ // internal state
+ u8 m_in_latch; // input latch
+ u8 m_out_latch; // output latch
+ u8 m_last_p2_value; // current P2 output value
+ optional_shared_ptr<u8> m_program_ram; // pointer to program RAM
+ required_shared_ptr<u8> m_work_ram; // pointer to work RAM
+ u8 m_work_ram_bank; // currently selected work RAM bank
+ u8 m_t1_clock; // T1 clock value
+ u8 m_t1_clock_mask; // T1 clock mask (configured via jumpers)
+
+protected:
+ // devices
+ required_device<i8035_device> m_ourcpu;
+ required_device<cpu_device> m_maincpu;
+
+private:
+#if (ENABLE_SEGAUSB_NETLIST)
+ // PIT devices
+ required_device_array<pit8253_device, 3> m_pit;
+
+ // channel 0
+ required_device_array<netlist_mame_analog_input_device, 3> m_nl_dac0;
+ required_device<netlist_mame_logic_input_device> m_nl_sel0;
+ required_device_array<netlist_mame_logic_input_device, 3> m_nl_pit0_out;
+
+ // channel 1
+ required_device_array<netlist_mame_analog_input_device, 3> m_nl_dac1;
+ required_device<netlist_mame_logic_input_device> m_nl_sel1;
+ required_device_array<netlist_mame_logic_input_device, 3> m_nl_pit1_out;
+
+ // channel 2
+ required_device_array<netlist_mame_analog_input_device, 3> m_nl_dac2;
+ required_device<netlist_mame_logic_input_device> m_nl_sel2;
+ required_device_array<netlist_mame_logic_input_device, 3> m_nl_pit2_out;
+
+ u8 m_gos_clock; // state of the GOD clock
+#else
+ struct g80_filter_state
+ {
+ g80_filter_state() { }
+
+ void configure(double r, double c);
+ double step_rc(double input) { return capval += (input - capval) * exponent; }
+ double step_cr(double input) { double const result = input - capval; capval += result * exponent; return result; }
+
+ double capval = 0.0; // current capacitor value
+ double exponent = 0.0; // constant exponent
+ };
+
+ struct timer8253
+ {
+ struct channel
+ {
+ channel() { }
+
+ void clock();
+
+ u8 holding = 0; // holding until counts written?
+ u8 latchmode = 0; // latching mode
+ u8 latchtoggle = 0; // latching state
+ u8 clockmode = 0; // clocking mode
+ u8 bcdmode = 0; // BCD mode?
+ u8 output = 0; // current output value
+ u8 lastgate = 0; // previous gate value
+ u8 gate = 0; // current gate value
+ u16 count = 0; // initial count
+ u16 remain = 0; // current down counter value
+ s32 subcount = 0; // subcount (2MHz clocks per input clock)
+ };
+
+ timer8253() : env{ 0.0, 0.0, 0.0 } { }
+
+ channel chan[3]; // three channels' worth of information
+ double env[3]; // envelope value for each channel
+ g80_filter_state chan_filter[2]; // filter states for the first two channels
+ g80_filter_state gate1; // first RC filter state
+ g80_filter_state gate2; // second RC filter state
+ u8 config = 0; // configuration for this timer
+ };
+
+ sound_stream *m_stream; // output stream
+ timer8253 m_timer_group[3]; // 3 groups of timers
+ u8 m_timer_mode[3]; // mode control for each group
+ u32 m_noise_shift;
+ u8 m_noise_state;
+ s32 m_noise_subcount;
+ double m_gate_rc1_exp[2];
+ double m_gate_rc2_exp[2];
+ g80_filter_state m_final_filter;
+ g80_filter_state m_noise_filters[5];
+#endif
+
+ TIMER_CALLBACK_MEMBER( delayed_usb_data_w );
+ void timer_w(int which, u8 offset, u8 data);
+ void env_w(int which, u8 offset, u8 data);
+
+ uint8_t p1_r();
+ void p1_w(uint8_t data);
+ void p2_w(uint8_t data);
+ DECLARE_READ_LINE_MEMBER( t1_r );
+};
+
+DECLARE_DEVICE_TYPE(SEGAUSB, usb_sound_device)
+
+
+class usb_rom_sound_device : public usb_sound_device
+{
+public:
+ template <typename T> usb_rom_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&maincpu_tag)
+ : usb_rom_sound_device(mconfig, tag, owner, clock)
+ {
+ m_maincpu.set_tag(maincpu_tag);
+ }
+
+ usb_rom_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+protected:
+ // device-level overrides
+ virtual void device_add_mconfig(machine_config &config) override;
+};
+
+DECLARE_DEVICE_TYPE(SEGAUSBROM, usb_rom_sound_device)
+
+#endif // MAME_AUDIO_SEGAUSB_H
diff --git a/src/mame/drivers/segag80r.cpp b/src/mame/drivers/segag80r.cpp
index 2a4092247ee..db74169b8e9 100644
--- a/src/mame/drivers/segag80r.cpp
+++ b/src/mame/drivers/segag80r.cpp
@@ -136,6 +136,11 @@
#define VBEND (0)
#define VBSTART (224)
+// Unsure whether this should be 2 or 3. It depends on how many rising clock
+// edges MEMRQ is held for, plus 1 additional cycle. Going to 3 creates
+// noticeable slowdowns in Space Fury.
+static constexpr int WAIT_STATES = 2;
+
/*************************************
@@ -856,8 +861,8 @@ void segag80r_state::astrob(machine_config &config)
SPEAKER(config, "speaker").front_center();
/* sound boards */
- astrob_sound_board(config);
- sega_speech_board(config);
+ ASTRO_BLASTER_AUDIO(config, m_g80_audio, 0).add_route(ALL_OUTPUTS, "speech", 1.0);
+ SEGA_SPEECH_BOARD(config, "speech", 0).add_route(ALL_OUTPUTS, "speaker", 0.5);
}
@@ -1007,19 +1012,21 @@ ROM_START( astrob )
ROM_LOAD( "924a.prom-u18", 0x9000, 0x0800, CRC(120a39c7) SHA1(d8fdf97290725cf9ebddab9eeb34d7adba097394) )
ROM_LOAD( "925a.prom-u19", 0x9800, 0x0800, CRC(790a7f4e) SHA1(16b7b8e864a8f5f59da6bf2ad17f1e4791f34abe) )
- ROM_REGION( 0x0800, "audiocpu", 0 )
+ ROM_REGION( 0x0800, "speech:cpu", 0 )
ROM_LOAD( "808b.speech-u7", 0x0000, 0x0800, CRC(5988c767) SHA1(3b91a8cd46aa7e714028cc40f700fea32287afb1) )
- ROM_REGION( 0x4000, SEGASND_SEGASPEECH_REGION, 0 )
+ ROM_REGION( 0x0020, "speech:proms", 0 )
+ ROM_LOAD( "pr84.speech-u30", 0x0000, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* 7051, speech board addressing */
+
+ ROM_REGION( 0x4000, "speech:data", 0 )
ROM_LOAD( "809a.speech-u6", 0x0000, 0x0800, CRC(893f228d) SHA1(41c08210d322105f5446cfaa1258c194dd078a34) )
ROM_LOAD( "810.speech-u5", 0x0800, 0x0800, CRC(ff0163c5) SHA1(158a12f9bf01d25c7e98f34fce56df51d49e5a85) )
ROM_LOAD( "811.speech-u4", 0x1000, 0x0800, CRC(219f3978) SHA1(728edb9251f7cde237fa3b005971366a099c6342) )
ROM_LOAD( "812a.speech-u3", 0x1800, 0x0800, CRC(410ad0d2) SHA1(9b5f05bb64a6ecfe3543025a10c6ec67de797333) )
- ROM_REGION( 0x0440, "proms", 0 ) // not dumped for this set, but believed identical
+ ROM_REGION( 0x0420, "proms", 0 ) // not dumped for this set, but believed identical
ROM_LOAD( "316-0806.video1-u52", 0x0000, 0x0020, CRC(358128b6) SHA1(b6b4b9ecfdcc69b45e69e7a8614153d83be4c62b) ) /* 6331 */
ROM_LOAD( "316-0764.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* 6331, CPU board addressing */
- ROM_LOAD( "pr84.speech-u30", 0x0420, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* 7051, speech board addressing */
ROM_END
ROM_START( astrob2 )
@@ -1045,19 +1052,21 @@ ROM_START( astrob2 )
ROM_LOAD( "905.prom-u18", 0x9000, 0x0800, CRC(4f08f9f4) SHA1(755a825b18ed50caa7bf274a0a5c3a1b00b1c070) )
ROM_LOAD( "906.prom-u19", 0x9800, 0x0800, CRC(58149df1) SHA1(2bba56576a225ca47ce31a5b6dcc491546dfffec) )
- ROM_REGION( 0x0800, "audiocpu", 0 )
+ ROM_REGION( 0x0800, "speech:cpu", 0 )
ROM_LOAD( "808b.speech-u7", 0x0000, 0x0800, CRC(5988c767) SHA1(3b91a8cd46aa7e714028cc40f700fea32287afb1) )
- ROM_REGION( 0x4000, SEGASND_SEGASPEECH_REGION, 0 )
+ ROM_REGION( 0x0020, "speech:proms", 0 )
+ ROM_LOAD( "pr84.speech-u30", 0x0000, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* 7051, speech board addressing */
+
+ ROM_REGION( 0x4000, "speech:data", 0 )
ROM_LOAD( "809a.speech-u6", 0x0000, 0x0800, CRC(893f228d) SHA1(41c08210d322105f5446cfaa1258c194dd078a34) )
ROM_LOAD( "810.speech-u5", 0x0800, 0x0800, CRC(ff0163c5) SHA1(158a12f9bf01d25c7e98f34fce56df51d49e5a85) )
ROM_LOAD( "811.speech-u4", 0x1000, 0x0800, CRC(219f3978) SHA1(728edb9251f7cde237fa3b005971366a099c6342) )
ROM_LOAD( "812a.speech-u3", 0x1800, 0x0800, CRC(410ad0d2) SHA1(9b5f05bb64a6ecfe3543025a10c6ec67de797333) )
- ROM_REGION( 0x0440, "proms", 0 ) // not dumped for this set, but believed identical
+ ROM_REGION( 0x0420, "proms", 0 ) // not dumped for this set, but believed identical
ROM_LOAD( "316-0806.video1-u52", 0x0000, 0x0020, CRC(358128b6) SHA1(b6b4b9ecfdcc69b45e69e7a8614153d83be4c62b) ) /* 6331 */
ROM_LOAD( "316-0764.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* 6331, CPU board addressing */
- ROM_LOAD( "pr84.speech-u30", 0x0420, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* 7051, speech board addressing */
ROM_END
ROM_START( astrob2a )
@@ -1083,19 +1092,21 @@ ROM_START( astrob2a )
ROM_LOAD( "905.prom-u18", 0x9000, 0x0800, CRC(4f08f9f4) SHA1(755a825b18ed50caa7bf274a0a5c3a1b00b1c070) )
ROM_LOAD( "906.prom-u19", 0x9800, 0x0800, CRC(58149df1) SHA1(2bba56576a225ca47ce31a5b6dcc491546dfffec) )
- ROM_REGION( 0x0800, "audiocpu", 0 )
+ ROM_REGION( 0x0800, "speech:cpu", 0 )
ROM_LOAD( "808b.speech-u7", 0x0000, 0x0800, CRC(5988c767) SHA1(3b91a8cd46aa7e714028cc40f700fea32287afb1) )
- ROM_REGION( 0x4000, SEGASND_SEGASPEECH_REGION, 0 )
+ ROM_REGION( 0x0020, "speech:proms", 0 )
+ ROM_LOAD( "pr84.speech-u30", 0x0000, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* 7051, speech board addressing */
+
+ ROM_REGION( 0x4000, "speech:data", 0 )
ROM_LOAD( "809a.speech-u6", 0x0000, 0x0800, CRC(893f228d) SHA1(41c08210d322105f5446cfaa1258c194dd078a34) )
ROM_LOAD( "810.speech-u5", 0x0800, 0x0800, CRC(ff0163c5) SHA1(158a12f9bf01d25c7e98f34fce56df51d49e5a85) )
ROM_LOAD( "811.speech-u4", 0x1000, 0x0800, CRC(219f3978) SHA1(728edb9251f7cde237fa3b005971366a099c6342) )
ROM_LOAD( "812a.speech-u3", 0x1800, 0x0800, CRC(410ad0d2) SHA1(9b5f05bb64a6ecfe3543025a10c6ec67de797333) )
- ROM_REGION( 0x0440, "proms", 0 )
+ ROM_REGION( 0x0420, "proms", 0 )
ROM_LOAD( "316-0806.video1-u52", 0x0000, 0x0020, CRC(358128b6) SHA1(b6b4b9ecfdcc69b45e69e7a8614153d83be4c62b) ) /* 6331 */
ROM_LOAD( "316-0764.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* 6331, CPU board addressing */
- ROM_LOAD( "pr84.speech-u30", 0x0420, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* 7051, speech board addressing */
ROM_END
ROM_START( astrob2b ) // This was dumped from 2 different PCB sets, with matching reads. Only different ROM from astrob2a is 829d.
@@ -1121,19 +1132,21 @@ ROM_START( astrob2b ) // This was dumped from 2 different PCB sets, with matchin
ROM_LOAD( "905.prom-u18", 0x9000, 0x0800, CRC(4f08f9f4) SHA1(755a825b18ed50caa7bf274a0a5c3a1b00b1c070) )
ROM_LOAD( "906.prom-u19", 0x9800, 0x0800, CRC(58149df1) SHA1(2bba56576a225ca47ce31a5b6dcc491546dfffec) )
- ROM_REGION( 0x0800, "audiocpu", 0 )
+ ROM_REGION( 0x0800, "speech:cpu", 0 )
ROM_LOAD( "808b.speech-u7", 0x0000, 0x0800, CRC(5988c767) SHA1(3b91a8cd46aa7e714028cc40f700fea32287afb1) )
- ROM_REGION( 0x4000, SEGASND_SEGASPEECH_REGION, 0 )
+ ROM_REGION( 0x0020, "speech:proms", 0 )
+ ROM_LOAD( "pr84.speech-u30", 0x0000, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* 7051, speech board addressing */
+
+ ROM_REGION( 0x4000, "speech:data", 0 )
ROM_LOAD( "809a.speech-u6", 0x0000, 0x0800, CRC(893f228d) SHA1(41c08210d322105f5446cfaa1258c194dd078a34) )
ROM_LOAD( "810.speech-u5", 0x0800, 0x0800, CRC(ff0163c5) SHA1(158a12f9bf01d25c7e98f34fce56df51d49e5a85) )
ROM_LOAD( "811.speech-u4", 0x1000, 0x0800, CRC(219f3978) SHA1(728edb9251f7cde237fa3b005971366a099c6342) )
ROM_LOAD( "812a.speech-u3", 0x1800, 0x0800, CRC(410ad0d2) SHA1(9b5f05bb64a6ecfe3543025a10c6ec67de797333) )
- ROM_REGION( 0x0440, "proms", 0 )
+ ROM_REGION( 0x0420, "proms", 0 )
ROM_LOAD( "316-0806.video1-u52", 0x0000, 0x0020, CRC(358128b6) SHA1(b6b4b9ecfdcc69b45e69e7a8614153d83be4c62b) ) /* 6331 */
ROM_LOAD( "316-0764.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* 6331, CPU board addressing */
- ROM_LOAD( "pr84.speech-u30", 0x0420, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* 7051, speech board addressing */
ROM_END
ROM_START( astrob1 )
@@ -1156,19 +1169,21 @@ ROM_START( astrob1 )
ROM_LOAD( "851.prom-u15", 0x7800, 0x0800, CRC(3d4cf9f0) SHA1(11e996f33f3a104e50d0a54a0814ea3e07735683) )
ROM_LOAD( "852.prom-u16", 0x8000, 0x0800, CRC(af88a97e) SHA1(fe7993101c629b296b5da05519b0990cc2b78286) )
- ROM_REGION( 0x0800, "audiocpu", 0 )
+ ROM_REGION( 0x0800, "speech:cpu", 0 )
ROM_LOAD( "808b.speech-u7", 0x0000, 0x0800, CRC(5988c767) SHA1(3b91a8cd46aa7e714028cc40f700fea32287afb1) )
- ROM_REGION( 0x4000, SEGASND_SEGASPEECH_REGION, 0 )
+ ROM_REGION( 0x0020, "speech:proms", 0 )
+ ROM_LOAD( "pr84.speech-u30", 0x0000, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* 7051, speech board addressing */
+
+ ROM_REGION( 0x4000, "speech:data", 0 )
ROM_LOAD( "809a.speech-u6", 0x0000, 0x0800, CRC(893f228d) SHA1(41c08210d322105f5446cfaa1258c194dd078a34) )
ROM_LOAD( "810.speech-u5", 0x0800, 0x0800, CRC(ff0163c5) SHA1(158a12f9bf01d25c7e98f34fce56df51d49e5a85) )
ROM_LOAD( "811.speech-u4", 0x1000, 0x0800, CRC(219f3978) SHA1(728edb9251f7cde237fa3b005971366a099c6342) )
ROM_LOAD( "812a.speech-u3", 0x1800, 0x0800, CRC(410ad0d2) SHA1(9b5f05bb64a6ecfe3543025a10c6ec67de797333) )
- ROM_REGION( 0x0440, "proms", 0 ) // not dumped for this set, but believed identical
+ ROM_REGION( 0x0420, "proms", 0 ) // not dumped for this set, but believed identical
ROM_LOAD( "316-0806.video1-u52", 0x0000, 0x0020, CRC(358128b6) SHA1(b6b4b9ecfdcc69b45e69e7a8614153d83be4c62b) ) /* 6331 */
ROM_LOAD( "316-0764.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* 6331, CPU board addressing */
- ROM_LOAD( "pr84.speech-u30", 0x0420, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* 7051, speech board addressing */
ROM_END
ROM_START( astrobg )
@@ -1191,19 +1206,21 @@ ROM_START( astrobg )
ROM_LOAD( "835.u15", 0x7800, 0x0800, CRC(6eeeb409) SHA1(1caf9b7ac08a4adcbf8c17f9e4b398373db706e1) )
ROM_LOAD( "836.u16", 0x8000, 0x0800, CRC(07ffe6dc) SHA1(70673e8266139034afa64bf980b1b9ddbf294e0f) )
- ROM_REGION( 0x0800, "audiocpu", 0 )
+ ROM_REGION( 0x0800, "speech:cpu", 0 )
ROM_LOAD( "808b_speech_de.u07", 0x0000, 0x0800, CRC(5988c767) SHA1(3b91a8cd46aa7e714028cc40f700fea32287afb1) )
- ROM_REGION( 0x4000, SEGASND_SEGASPEECH_REGION, 0 )
+ ROM_REGION( 0x0020, "speech:proms", 0 )
+ ROM_LOAD( "pr84.speech-u30", 0x0000, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* 7051, speech board addressing */
+
+ ROM_REGION( 0x4000, "speech:data", 0 )
ROM_LOAD( "830_speech_de.u06", 0x0000, 0x0800, CRC(2d840552) SHA1(7a2a7b54378b6cc85b8ab5c26e42266aa747c635) )
ROM_LOAD( "831_speech_de.u05", 0x0800, 0x0800, CRC(46b30ee4) SHA1(c9e19a9b9ebc9b3b853e79f93ad74e4ec5dfd1ae) )
ROM_LOAD( "832_speech_de.u04", 0x1000, 0x0800, CRC(d05280b8) SHA1(8d30b23b83b32465a8a2decd2ce9bfed24394e7e) )
ROM_LOAD( "833_speech_de.u03", 0x1800, 0x0800, CRC(08f11459) SHA1(da6dc2bf30b95882f95c21739ec02fc89d286a66) )
- ROM_REGION( 0x0440, "proms", 0 ) // not dumped for this set, but believed identical
+ ROM_REGION( 0x0420, "proms", 0 ) // not dumped for this set, but believed identical
ROM_LOAD( "316-0806.video1-u52", 0x0000, 0x0020, CRC(358128b6) SHA1(b6b4b9ecfdcc69b45e69e7a8614153d83be4c62b) ) /* 6331 */
ROM_LOAD( "316-0764.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* 6331, CPU board addressing */
- ROM_LOAD( "pr84.speech-u30", 0x0420, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* 7051, speech board addressing */
ROM_END
ROM_START( 005 )
@@ -1526,8 +1543,36 @@ void segag80r_state::monsterb_expand_gfx(const char *region)
*
*************************************/
+void segag80r_state::init_waitstates()
+{
+ address_space &pgmspace = m_maincpu->space(AS_PROGRAM);
+ address_space &opspace = m_maincpu->space(AS_OPCODES);
+
+ pgmspace.install_read_tap(0x0000, 0xffff, "program_waitstate_r",[this](offs_t offset, u8 &data, u8 mem_mask)
+ {
+ if (!machine().side_effects_disabled())
+ m_maincpu->adjust_icount(-WAIT_STATES);
+ return data;
+ });
+ pgmspace.install_write_tap(0x0000, 0xffff, "program_waitstate_w",[this](offs_t offset, u8 &data, u8 mem_mask)
+ {
+ if (!machine().side_effects_disabled())
+ m_maincpu->adjust_icount(-WAIT_STATES);
+ return data;
+ });
+
+ opspace.install_read_tap(0x0000, 0xffff, "opcodes_waitstate_r",[this](offs_t offset, u8 &data, u8 mem_mask)
+ {
+ if (!machine().side_effects_disabled())
+ m_maincpu->adjust_icount(-WAIT_STATES);
+ return data;
+ });
+}
+
void segag80r_state::init_astrob()
{
+ init_waitstates();
+
address_space &iospace = m_maincpu->space(AS_IO);
/* configure the 315-0062 security chip */
@@ -1537,19 +1582,18 @@ void segag80r_state::init_astrob()
m_background_pcb = G80_BACKGROUND_NONE;
/* install speech board */
- iospace.install_write_handler(0x38, 0x38, write8smo_delegate(*m_speech, FUNC(speech_sound_device::data_w)));
- iospace.install_write_handler(0x3b, 0x3b, write8smo_delegate(*m_speech, FUNC(speech_sound_device::control_w)));
+ iospace.install_write_handler(0x38, 0x38, write8smo_delegate(*m_speech, FUNC(sega_speech_device::data_w)));
+ iospace.install_write_handler(0x3b, 0x3b, write8smo_delegate(*m_speech, FUNC(sega_speech_device::control_w)));
/* install Astro Blaster sound board */
- iospace.install_write_handler(0x3e, 0x3f, write8sm_delegate(*this, FUNC(segag80r_state::astrob_sound_w)));
-
- save_item(NAME(m_sound_state));
- save_item(NAME(m_sound_rate));
+ iospace.install_write_handler(0x3e, 0x3f, write8sm_delegate(*m_g80_audio, FUNC(segag80_audio_device::write)));
}
void segag80r_state::init_005()
{
+ init_waitstates();
+
/* configure the 315-0070 security chip */
m_decrypt = segag80_security(70);
@@ -1566,6 +1610,8 @@ void segag80r_state::init_005()
void segag80r_state::init_spaceod()
{
+ init_waitstates();
+
address_space &iospace = m_maincpu->space(AS_IO);
/* configure the 315-0063 security chip */
@@ -1590,6 +1636,8 @@ void segag80r_state::init_spaceod()
void segag80r_state::init_monsterb()
{
+ init_waitstates();
+
address_space &iospace = m_maincpu->space(AS_IO);
address_space &pgmspace = m_maincpu->space(AS_PROGRAM);
@@ -1611,6 +1659,8 @@ void segag80r_state::init_monsterb()
void segag80r_state::init_monster2()
{
+ init_waitstates();
+
address_space &iospace = m_maincpu->space(AS_IO);
address_space &pgmspace = m_maincpu->space(AS_PROGRAM);
@@ -1633,6 +1683,8 @@ void segag80r_state::init_monster2()
void segag80r_state::init_pignewt()
{
+ init_waitstates();
+
address_space &iospace = m_maincpu->space(AS_IO);
address_space &pgmspace = m_maincpu->space(AS_PROGRAM);
@@ -1657,6 +1709,8 @@ void segag80r_state::init_pignewt()
void segag80r_state::init_sindbadm()
{
+ init_waitstates();
+
address_space &iospace = m_maincpu->space(AS_IO);
address_space &pgmspace = m_maincpu->space(AS_PROGRAM);
@@ -1681,12 +1735,12 @@ void segag80r_state::init_sindbadm()
// YEAR, NAME, PARENT, MACHINE, INPUT, CLASS, INIT, MONITOR,COMPANY,FULLNAME,FLAGS
/* basic G-80 system with: CPU board, PROM board, Video I board, custom sound boards */
-GAME( 1981, astrob, 0, astrob, astrob, segag80r_state, init_astrob, ROT270, "Sega", "Astro Blaster (version 3)", MACHINE_IMPERFECT_SOUND )
-GAME( 1981, astrob2, astrob, astrob, astrob2, segag80r_state, init_astrob, ROT270, "Sega", "Astro Blaster (version 2)", MACHINE_IMPERFECT_SOUND )
-GAME( 1981, astrob2a, astrob, astrob, astrob2, segag80r_state, init_astrob, ROT270, "Sega", "Astro Blaster (version 2a)", MACHINE_IMPERFECT_SOUND )
-GAME( 1981, astrob2b, astrob, astrob, astrob2, segag80r_state, init_astrob, ROT270, "Sega", "Astro Blaster (version 2b)", MACHINE_IMPERFECT_SOUND )
-GAME( 1981, astrob1, astrob, astrob, astrob, segag80r_state, init_astrob, ROT270, "Sega", "Astro Blaster (version 1)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) // instant death if you start game with 1 credit, protection?, bad dump?
-GAME( 1981, astrobg, astrob, astrob, astrob, segag80r_state, init_astrob, ROT270, "Sega", "Astro Blaster (German)", MACHINE_IMPERFECT_SOUND )
+GAME( 1981, astrob, 0, astrob, astrob, segag80r_state, init_astrob, ROT270, "Sega", "Astro Blaster (version 3)", 0 )
+GAME( 1981, astrob2, astrob, astrob, astrob2, segag80r_state, init_astrob, ROT270, "Sega", "Astro Blaster (version 2)", 0 )
+GAME( 1981, astrob2a, astrob, astrob, astrob2, segag80r_state, init_astrob, ROT270, "Sega", "Astro Blaster (version 2a)", 0 )
+GAME( 1981, astrob2b, astrob, astrob, astrob2, segag80r_state, init_astrob, ROT270, "Sega", "Astro Blaster (version 2b)", 0 )
+GAME( 1981, astrob1, astrob, astrob, astrob, segag80r_state, init_astrob, ROT270, "Sega", "Astro Blaster (version 1)", 0 | MACHINE_NOT_WORKING ) // instant death if you start game with 1 credit, protection?, bad dump?
+GAME( 1981, astrobg, astrob, astrob, astrob, segag80r_state, init_astrob, ROT270, "Sega", "Astro Blaster (German)", 0 )
GAME( 1981, 005, 0, sega005, 005, segag80r_state, init_005, ROT270, "Sega", "005", MACHINE_IMPERFECT_SOUND )
diff --git a/src/mame/drivers/segag80v.cpp b/src/mame/drivers/segag80v.cpp
index 0019926832d..b8da53afa46 100644
--- a/src/mame/drivers/segag80v.cpp
+++ b/src/mame/drivers/segag80v.cpp
@@ -135,6 +135,7 @@
***************************************************************************/
#include "emu.h"
+#include "audio/segag80.h"
#include "includes/segag80v.h"
#include "machine/segag80.h"
@@ -143,15 +144,10 @@
#include "speaker.h"
-/*************************************
- *
- * Constants
- *
- *************************************/
-
-#define CPU_CLOCK 8000000 /* not used when video boards are connected */
-#define VIDEO_CLOCK 15468480
-
+// Unsure whether this should be 2 or 3. It depends on how many rising clock
+// edges MEMRQ is held for, plus 1 additional cycle. Going to 3 creates
+// noticeable slowdowns in Space Fury.
+static constexpr int WAIT_STATES = 2;
/*************************************
@@ -160,10 +156,10 @@
*
*************************************/
-INPUT_CHANGED_MEMBER(segag80v_state::service_switch)
+WRITE_LINE_MEMBER(segag80v_state::service_switch_w)
{
- /* pressing the service switch sends an NMI */
- if (newval)
+ // pressing the service switch sends an NMI
+ if (state)
m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
}
@@ -172,13 +168,15 @@ void segag80v_state::machine_start()
{
m_scrambled_write_pc = 0xffff;
- /* register for save states */
save_item(NAME(m_mult_data));
save_item(NAME(m_mult_result));
save_item(NAME(m_spinner_select));
save_item(NAME(m_spinner_sign));
save_item(NAME(m_spinner_count));
save_item(NAME(m_scrambled_write_pc));
+ save_item(NAME(m_coin_ff_state));
+ save_item(NAME(m_coin_last_state));
+ save_item(NAME(m_edgint_ff_state));
}
@@ -189,10 +187,10 @@ void segag80v_state::machine_start()
*
*************************************/
-uint8_t segag80v_state::g80v_opcode_r(offs_t offset)
+u8 segag80v_state::opcode_r(offs_t offset)
{
// opcodes themselves are not scrambled
- uint8_t op = m_maincpu->space(AS_PROGRAM).read_byte(offset);
+ u8 op = m_maincpu->space(AS_PROGRAM).read_byte(offset);
// writes via opcode $32 (LD $(XXYY),A) get scrambled
if (!machine().side_effects_disabled())
@@ -209,17 +207,21 @@ offs_t segag80v_state::decrypt_offset(offs_t offset)
offs_t pc = m_scrambled_write_pc;
m_scrambled_write_pc = 0xffff;
- /* munge the low byte of the address */
+ // munge the low byte of the address
return (offset & 0xff00) | (*m_decrypt)(pc, offset & 0xff);
}
-void segag80v_state::mainram_w(offs_t offset, uint8_t data)
+void segag80v_state::mainram_w(offs_t offset, u8 data)
{
m_mainram[decrypt_offset(offset)] = data;
}
-void segag80v_state::usb_ram_w(offs_t offset, uint8_t data){ m_usb->ram_w(decrypt_offset(offset), data); }
-void segag80v_state::vectorram_w(offs_t offset, uint8_t data)
+void segag80v_state::usb_ram_w(offs_t offset, u8 data)
+{
+ m_usb->ram_w(decrypt_offset(offset), data);
+}
+
+void segag80v_state::vectorram_w(offs_t offset, u8 data)
{
m_vectorram[decrypt_offset(offset)] = data;
}
@@ -232,28 +234,50 @@ void segag80v_state::vectorram_w(offs_t offset, uint8_t data)
*
*************************************/
-inline uint8_t segag80v_state::demangle(uint8_t d7d6, uint8_t d5d4, uint8_t d3d2, uint8_t d1d0)
+//
+// I/O port mapping
+//
+// +--------------- Offset-----------------+
+// | 0 | 1 | 2 | 3 |
+// +----+---------+---------+---------+---------+
+// | D7 | COINA | n/c | n/c | n/c |
+// | D6 | COINB | P1.13 | P1.14 | n/c |
+// | D5 | SERVICE | P1.15 | P1.16 | P1.17 |
+// | D4 | P1.18 | P1.19 | P1.20 | P1.21 |
+// | D3 | SW1.8 | SW1.7 | SW1.6 | SW1.5 |
+// | D2 | SW1.4 | SW1.3 | SW1.2 | SW1.1 |
+// | D1 | SW2.8 | SW2.7 | SW2.6 | SW2.5 |
+// | D0 | SW2.4 | SW2.3 | SW2.2 | SW2.1 |
+// +----+---------+---------+---------+---------+
+//
+// Notes:
+// COINA, COINB are gated to be impulses, and signal an INT
+// SERVICE is gated to be an impulse, but does not signal
+// P1.13 = DRAW signal from XY board
+//
+// The input ports are mapped to how the schematics show them, so
+// to achieve the matrix above, they must be demangled.
+//
+
+u8 segag80v_state::mangled_ports_r(offs_t offset)
{
- return ((d7d6 << 7) & 0x80) | ((d7d6 << 2) & 0x40) |
- ((d5d4 << 5) & 0x20) | ((d5d4 << 0) & 0x10) |
- ((d3d2 << 3) & 0x08) | ((d3d2 >> 2) & 0x04) |
- ((d1d0 << 1) & 0x02) | ((d1d0 >> 4) & 0x01);
-}
+ u8 d7d6 = m_d7d6->read();
+ u8 d5d4 = m_d5d4->read();
+ u8 d3d2 = m_d3d2->read();
+ u8 d1d0 = m_d1d0->read();
+
+ offset &= 3;
+ u8 result =
+ (BIT(d7d6, offset + 0) << 7) |
+ (BIT(d7d6, offset + 4) << 6) |
+ (BIT(d5d4, offset + 0) << 5) |
+ (BIT(d5d4, offset + 4) << 4) |
+ (BIT(d3d2, offset + 0) << 3) |
+ (BIT(d3d2, offset + 4) << 2) |
+ (BIT(d1d0, offset + 0) << 1) |
+ (BIT(d1d0, offset + 4) << 0);
-
-uint8_t segag80v_state::mangled_ports_r(offs_t offset)
-{
- /* The input ports are odd. Neighboring lines are read via a mux chip */
- /* one bit at a time. This means that one bank of DIP switches will be */
- /* read as two bits from each of 4 ports. For this reason, the input */
- /* ports have been organized logically, and are demangled at runtime. */
- /* 4 input ports each provide 8 bits of information. */
- uint8_t d7d6 = ioport("D7D6")->read();
- uint8_t d5d4 = ioport("D5D4")->read();
- uint8_t d3d2 = ioport("D3D2")->read();
- uint8_t d1d0 = ioport("D1D0")->read();
- int shift = offset & 3;
- return demangle(d7d6 >> shift, d5d4 >> shift, d3d2 >> shift, d1d0 >> shift);
+ return result;
}
@@ -264,28 +288,24 @@ uint8_t segag80v_state::mangled_ports_r(offs_t offset)
*
*************************************/
-void segag80v_state::spinner_select_w(uint8_t data)
+void segag80v_state::spinner_select_w(u8 data)
{
m_spinner_select = data;
}
-uint8_t segag80v_state::spinner_input_r()
+u8 segag80v_state::spinner_input_r()
{
- int8_t delta;
-
if (m_spinner_select & 1)
- return ioport("FC")->read();
-
-/*
- * The values returned are always increasing. That is, regardless of whether
- * you turn the spinner left or right, the self-test should always show the
- * number as increasing. The direction is only reflected in the least
- * significant bit.
- */
-
- /* I'm sure this can be further simplified ;-) BW */
- delta = ioport("SPINNER")->read();
+ return m_fc->read();
+
+ //
+ // The values returned are always increasing. That is, regardless of whether
+ // you turn the spinner left or right, the self-test should always show the
+ // number as increasing. The direction is only reflected in the least
+ // significant bit.
+ //
+ s8 delta = m_spinner->read();
if (delta != 0)
{
m_spinner_sign = (delta >> 7) & 1;
@@ -304,32 +324,33 @@ uint8_t segag80v_state::spinner_input_r()
READ_LINE_MEMBER(segag80v_state::elim4_joint_coin_r)
{
- return (ioport("COINS")->read() & 0xf) != 0xf;
+ return (m_coins->read() & 0xf) != 0xf;
}
-uint8_t segag80v_state::elim4_input_r()
+u8 segag80v_state::elim4_input_r()
{
- uint8_t result = 0;
+ u8 result = 0;
- /* bit 3 enables demux */
- if (m_spinner_select & 8)
+ // bit 3 enables demux
+ if (BIT(m_spinner_select, 3) != 0)
{
- /* Demux bit 0-2. Only 6 and 7 are connected */
+ // Demux bit 0-2. Only 6 and 7 are connected
switch (m_spinner_select & 7)
{
case 6:
- /* player 3 & 4 controls */
- result = ioport("FC")->read();
+ // player 3 & 4 controls
+ result = m_fc->read();
break;
+
case 7:
- /* the 4 coin inputs */
- result = ioport("COINS")->read();
+ // the 4 coin inputs
+ result = m_coins->read();
break;
}
}
- /* LS240 has inverting outputs */
+ // LS240 has inverting outputs
return (result ^ 0xff);
}
@@ -341,7 +362,7 @@ uint8_t segag80v_state::elim4_input_r()
*
*************************************/
-void segag80v_state::multiply_w(offs_t offset, uint8_t data)
+void segag80v_state::multiply_w(offs_t offset, u8 data)
{
m_mult_data[offset] = data;
if (offset == 1)
@@ -349,9 +370,9 @@ void segag80v_state::multiply_w(offs_t offset, uint8_t data)
}
-uint8_t segag80v_state::multiply_r()
+u8 segag80v_state::multiply_r()
{
- uint8_t result = m_mult_result;
+ u8 result = m_mult_result;
m_mult_result >>= 8;
return result;
}
@@ -364,21 +385,76 @@ uint8_t segag80v_state::multiply_r()
*
*************************************/
-void segag80v_state::coin_count_w(uint8_t data)
+void segag80v_state::coin_count_w(u8 data)
{
machine().bookkeeping().coin_counter_w(0, (data >> 7) & 1);
machine().bookkeeping().coin_counter_w(1, (data >> 6) & 1);
}
-void segag80v_state::unknown_w(uint8_t data)
+void segag80v_state::unknown_w(u8 data)
{
- /* writing an 0x04 here enables interrupts */
- /* some games write 0x00/0x01 here as well */
+ // writing an 0x04 here enables interrupts
+ // some games write 0x00/0x01 here as well
if (data != 0x00 && data != 0x01 && data != 0x04)
osd_printf_debug("%04X:unknown_w = %02X\n", m_maincpu->pc(), data);
}
+READ_LINE_MEMBER(segag80v_state::draw_r)
+{
+ return (machine().scheduler().time() < m_draw_end_time);
+}
+
+
+
+/*************************************
+ *
+ * Main CPU interrupts
+ *
+ *************************************/
+
+void segag80v_state::vblank_callback(screen_device &screen, bool state)
+{
+ if (!state)
+ {
+ m_edgint_ff_state = 1;
+ update_int();
+ }
+}
+
+void segag80v_state::update_int()
+{
+ //
+ // IRQ signal comes from multiple sources:
+ // * XINT signal, which is a combination of:
+ // - COINA impulse, clocks an LS74, cleared by INTCL signal
+ // - COINB impulse, clocks an LS74, cleared by INTCL signal
+ // - SERVICE impulse
+ // * /EDGINT signal from vector board, clocks an LS74, cleared by INTCL signal
+ // - signal comes from 15468480 crystal, divided by 3, and then by 0x1f788
+ // * /INT signal from ???
+ //
+
+ if (m_coin_ff_state != 0 || m_edgint_ff_state != 0)
+ m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
+ else
+ m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
+
+ // SERVICE coin doesn't have a flip-flop; it's instantaneous
+ m_coin_ff_state &= ~0x04;
+}
+
+WRITE_LINE_MEMBER(segag80v_state::irq_ack_w)
+{
+ if (state)
+ {
+ // INTCL signal clears both coin flip-flops and EDGINT flip-flop
+ m_coin_ff_state = 0;
+ m_edgint_ff_state = 0;
+ update_int();
+ }
+}
+
/*************************************
@@ -387,26 +463,26 @@ void segag80v_state::unknown_w(uint8_t data)
*
*************************************/
-/* complete memory map derived from schematics */
+// complete memory map derived from schematics
void segag80v_state::main_map(address_map &map)
{
- map(0x0000, 0x07ff).rom(); /* CPU board ROM */
- map(0x0800, 0xbfff).rom(); /* PROM board ROM area */
+ map(0x0000, 0x07ff).rom(); // CPU board ROM
+ map(0x0800, 0xbfff).rom(); // PROM board ROM area
map(0xc800, 0xcfff).ram().w(FUNC(segag80v_state::mainram_w)).share("mainram");
map(0xe000, 0xefff).ram().w(FUNC(segag80v_state::vectorram_w)).share("vectorram");
}
void segag80v_state::opcodes_map(address_map &map)
{
- map(0x0000, 0xffff).r(FUNC(segag80v_state::g80v_opcode_r));
+ map(0x0000, 0xffff).r(FUNC(segag80v_state::opcode_r));
}
-/* complete memory map derived from schematics */
+// complete memory map derived from schematics
void segag80v_state::main_portmap(address_map &map)
{
map.global_mask(0xff);
- map(0xbc, 0xbc); /* .r(FUNC(segag80v_state::)); ??? */
+ map(0xbc, 0xbc); // .r(FUNC(segag80v_state::)); ???
map(0xbd, 0xbe).w(FUNC(segag80v_state::multiply_w));
map(0xbe, 0xbe).r(FUNC(segag80v_state::multiply_r));
map(0xbf, 0xbf).w(FUNC(segag80v_state::unknown_w));
@@ -426,24 +502,24 @@ void segag80v_state::main_portmap(address_map &map)
static INPUT_PORTS_START( g80v_generic )
PORT_START("D7D6")
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(3) /* P1.5 */
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) /* n/c */
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) /* n/c */
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) /* n/c */
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_COIN2 ) PORT_IMPULSE(3) /* P1.8 */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) /* P1.13 */
- PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) /* P1.14 */
- PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) /* n/c */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_WRITE_LINE_MEMBER(segag80v_state, coin_w<0>) // P1.5
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) // n/c
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) // n/c
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) // n/c
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_COIN2 ) PORT_WRITE_LINE_MEMBER(segag80v_state, coin_w<1>) // P1.8
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(segag80v_state, draw_r) // P1.13
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // P1.14
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // n/c
PORT_START("D5D4")
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SERVICE1 ) /* P1.10 */
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START1 ) /* P1.15 */
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) /* P1.16 */
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) /* P1.17 */
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) /* P1.18 */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START2 ) /* P1.19 */
- PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) /* P1.20 */
- PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) /* P1.21 */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_WRITE_LINE_MEMBER(segag80v_state, coin_w<2>) // P1.10
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START1 ) // P1.15
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) // P1.16
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) // P1.17
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // P1.18
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START2 ) // P1.19
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // P1.20
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // P1.21
PORT_START("D3D2")
PORT_DIPUNUSED_DIPLOC( 0x01, 0x01, "SW1:8" )
@@ -492,17 +568,17 @@ static INPUT_PORTS_START( g80v_generic )
PORT_DIPSETTING( 0x80, DEF_STR( 1C_6C ))
PORT_START("FC")
- PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) /* P1.23 */
- PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) /* P1.24 */
- PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) /* P1.25 */
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) /* P1.26 */
- PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) /* P1.27 */
- PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) /* P1.28 */
- PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) /* P1.29 */
- PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) /* P1.30 */
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // P1.23
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) // P1.24
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) // P1.25
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) // P1.26
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) // P1.27
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) // P1.28
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) // P1.29
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) // P1.30
PORT_START("SERVICESW")
- PORT_SERVICE_NO_TOGGLE( 0x01, IP_ACTIVE_HIGH ) PORT_CHANGED_MEMBER(DEVICE_SELF, segag80v_state,service_switch, 0)
+ PORT_SERVICE_NO_TOGGLE( 0x01, IP_ACTIVE_HIGH ) PORT_WRITE_LINE_MEMBER(segag80v_state, service_switch_w)
INPUT_PORTS_END
@@ -714,8 +790,8 @@ static INPUT_PORTS_START( zektor )
PORT_DIPSETTING( 0x40, "30000" )
PORT_MODIFY("D5D4")
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) /* P1.15 */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) /* P1.19 */
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) // P1.15
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // P1.19
PORT_MODIFY("FC")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_START1 )
@@ -755,8 +831,8 @@ static INPUT_PORTS_START( tacscan )
PORT_DIPSETTING( 0x40, "30000" )
PORT_MODIFY("D5D4")
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) /* P1.15 */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) /* P1.19 */
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) // P1.15
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // P1.19
PORT_MODIFY("FC")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_START1 )
@@ -796,8 +872,8 @@ static INPUT_PORTS_START( startrek )
PORT_DIPSETTING( 0xc0, "40000" )
PORT_MODIFY("D5D4")
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) /* P1.15 */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) /* P1.19 */
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) // P1.15
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // P1.19
PORT_MODIFY("FC")
@@ -816,161 +892,65 @@ INPUT_PORTS_END
/*************************************
*
- * Eliminator sound interfaces
- *
- *************************************/
-
-static const char *const elim_sample_names[] =
-{
- "*elim2",
- "elim1",
- "elim2",
- "elim3",
- "elim4",
- "elim5",
- "elim6",
- "elim7",
- "elim8",
- "elim9",
- "elim10",
- "elim11",
- "elim12",
- nullptr /* end of array */
-};
-
-
-/*************************************
- *
- * Space Fury sound interfaces
- *
- *************************************/
-
-static const char *const spacfury_sample_names[] =
-{
- "*spacfury",
- /* Sound samples */
- "sfury1",
- "sfury2",
- "sfury3",
- "sfury4",
- "sfury5",
- "sfury6",
- "sfury7",
- "sfury8",
- "sfury9",
- "sfury10",
- nullptr /* end of array */
-};
-
-/*************************************
- *
- * Zektor sound interfaces
- *
- *************************************/
-
-static const char *const zektor_sample_names[] =
-{
- "*zektor",
- "elim1", /* 0 fireball */
- "elim2", /* 1 bounce */
- "elim3", /* 2 Skitter */
- "elim4", /* 3 Eliminator */
- "elim5", /* 4 Electron */
- "elim6", /* 5 fire */
- "elim7", /* 6 thrust */
- "elim8", /* 7 Electron */
- "elim9", /* 8 small explosion */
- "elim10", /* 9 med explosion */
- "elim11", /* 10 big explosion */
- nullptr
-};
-
-
-/*************************************
- *
* Machine drivers
*
*************************************/
void segag80v_state::g80v_base(machine_config &config)
{
- /* basic machine hardware */
+ // basic machine hardware
Z80(config, m_maincpu, VIDEO_CLOCK/4);
m_maincpu->set_addrmap(AS_PROGRAM, &segag80v_state::main_map);
m_maincpu->set_addrmap(AS_OPCODES, &segag80v_state::opcodes_map);
m_maincpu->set_addrmap(AS_IO, &segag80v_state::main_portmap);
- m_maincpu->set_vblank_int("screen", FUNC(segag80v_state::irq0_line_hold));
+ m_maincpu->irqack_cb().set(FUNC(segag80v_state::irq_ack_w));
+// m_maincpu->set_vblank_int("screen", FUNC(segag80v_state::irq0_line_hold));
- /* video hardware */
+ // video hardware
SCREEN(config, m_screen, SCREEN_TYPE_VECTOR);
m_screen->set_refresh_hz(40);
m_screen->set_size(400, 300);
m_screen->set_visarea(512, 1536, 640-32, 1408+32);
m_screen->set_screen_update(FUNC(segag80v_state::screen_update_segag80v));
+ m_screen->register_vblank_callback(vblank_state_delegate(&segag80v_state::vblank_callback, this));
VECTOR(config, m_vector);
- /* sound hardware */
+ // sound hardware
SPEAKER(config, "speaker").front_center();
}
void segag80v_state::elim2(machine_config &config)
{
g80v_base(config);
-
- /* custom sound board */
- SAMPLES(config, m_samples);
- m_samples->set_channels(8);
- m_samples->set_samples_names(elim_sample_names);
- m_samples->add_route(ALL_OUTPUTS, "speaker", 1.0);
+ ELIMINATOR_AUDIO(config, m_g80_audio, 0).add_route(ALL_OUTPUTS, "speaker", 1.0);
}
void segag80v_state::spacfury(machine_config &config)
{
g80v_base(config);
-
- /* custom sound board */
- SAMPLES(config, m_samples);
- m_samples->set_channels(8);
- m_samples->set_samples_names(spacfury_sample_names);
- m_samples->add_route(ALL_OUTPUTS, "speaker", 0.1);
-
- /* speech board */
- sega_speech_board(config);
+ SPACE_FURY_AUDIO(config, m_g80_audio, 0).add_route(ALL_OUTPUTS, "speech", 1.0);
+ SEGA_SPEECH_BOARD(config, "speech", 0).add_route(ALL_OUTPUTS, "speaker", 1.0);
}
void segag80v_state::zektor(machine_config &config)
{
g80v_base(config);
-
- /* custom sound board */
- SAMPLES(config, m_samples);
- m_samples->set_channels(8);
- m_samples->set_samples_names(zektor_sample_names);
- m_samples->add_route(ALL_OUTPUTS, "speaker", 0.1);
-
- AY8912(config, m_aysnd, VIDEO_CLOCK/4/2).add_route(ALL_OUTPUTS, "speaker", 0.33);
-
- /* speech board */
- sega_speech_board(config);
+ ZEKTOR_AUDIO(config, m_g80_audio, 0).add_route(ALL_OUTPUTS, "speech", 0.7);
+ SEGA_SPEECH_BOARD(config, "speech", 0).add_route(ALL_OUTPUTS, "speaker", 1.0);
}
-
void segag80v_state::tacscan(machine_config &config)
{
g80v_base(config);
-
- /* universal sound board */
SEGAUSB(config, m_usb, 0, m_maincpu).add_route(ALL_OUTPUTS, "speaker", 1.0);
}
-
void segag80v_state::startrek(machine_config &config)
{
- tacscan(config);
-
- /* speech board */
- sega_speech_board(config);
+ g80v_base(config);
+ SEGAUSB(config, m_usb, 0, m_maincpu).add_route(ALL_OUTPUTS, "speech", 1.0);
+ SEGA_SPEECH_BOARD(config, "speech", 0).add_route(ALL_OUTPUTS, "speaker", 1.0);
}
@@ -999,8 +979,8 @@ ROM_START( elim2 )
ROM_LOAD( "1345.prom-u13", 0x6800, 0x0800, CRC(40597a92) SHA1(ee1ae2b424c38b40d2cbeda4aba3328e6d3f9c81) )
ROM_REGION( 0x0420, "proms", 0 )
- ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) /* sine table */
- ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* CPU board addressing */
+ ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) // sine table
+ ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) // CPU board addressing
ROM_END
ROM_START( elim2a )
@@ -1021,8 +1001,8 @@ ROM_START( elim2a )
ROM_LOAD( "1170a.prom-u13", 0x6800, 0x0800, CRC(8cdacd35) SHA1(f24f8a74cb4b8452ddbd42e61d3b0366bbee7f98) )
ROM_REGION( 0x0420, "proms", 0 )
- ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) /* sine table */
- ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* CPU board addressing */
+ ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) // sine table
+ ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) // CPU board addressing
ROM_END
ROM_START( elim2c )
@@ -1043,8 +1023,8 @@ ROM_START( elim2c )
ROM_LOAD( "1212.prom-u13", 0x6800, 0x0800, CRC(152cf376) SHA1(56c3141598b8bac81e85b1fc7052fdd19cd95609) )
ROM_REGION( 0x0420, "proms", 0 )
- ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) /* sine table */
- ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* CPU board addressing */
+ ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) // sine table
+ ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) // CPU board addressing
ROM_END
ROM_START( elim4 )
@@ -1066,8 +1046,8 @@ ROM_START( elim4 )
ROM_LOAD( "1360.prom-u14", 0x7000, 0x0800, CRC(96d48238) SHA1(76a7b49081cd2d0dd1976077aa66b6d5ae5b2b43) )
ROM_REGION( 0x0420, "proms", 0 )
- ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) /* sine table */
- ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* CPU board addressing */
+ ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) // sine table
+ ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) // CPU board addressing
ROM_END
ROM_START( elim4p )
@@ -1089,12 +1069,12 @@ ROM_START( elim4p )
ROM_LOAD( "swe.prom-u14", 0x7000, 0x0800, CRC(ec4cc343) SHA1(00e107eaf530ce6bec2afffd7d7bedd7763cfb17) )
ROM_REGION( 0x0420, "proms", 0 )
- ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) /* sine table */
- ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* CPU board addressing */
+ ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) // sine table
+ ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) // CPU board addressing
ROM_END
-ROM_START( spacfury ) /* Revision C */
+ROM_START( spacfury ) // Revision C
ROM_REGION( 0xc000, "maincpu", 0 )
ROM_LOAD( "969c.cpu-u25", 0x0000, 0x0800, CRC(411207f2) SHA1(2a082be4052b5d8f365abd0a51ea805d270d1189) )
ROM_LOAD( "960c.prom-u1", 0x0800, 0x0800, CRC(d071ab7e) SHA1(c7d2429e4fa77988d7ac62bc68f876ffb7467838) )
@@ -1107,21 +1087,23 @@ ROM_START( spacfury ) /* Revision C */
ROM_LOAD( "967c.prom-u8", 0x4000, 0x0800, CRC(330f0751) SHA1(07ae52fdbfa2cc326f88dc76c3dc8e145b592863) )
ROM_LOAD( "968c.prom-u9", 0x4800, 0x0800, CRC(8366eadb) SHA1(8e4cb30a730237da2e933370faf5eaa1a41cacbf) )
- ROM_REGION( 0x0800, "audiocpu", 0 )
+ ROM_REGION( 0x0800, "speech:cpu", 0 )
ROM_LOAD( "808c.speech-u7", 0x0000, 0x0800, CRC(b779884b) SHA1(ac07e99717a1f51b79f3e43a5d873ebfa0559320) )
- ROM_REGION( 0x4000, SEGASND_SEGASPEECH_REGION, 0 )
+ ROM_REGION( 0x0020, "speech:proms", 0 )
+ ROM_LOAD( "6331.speech-u30", 0x0000, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) // speech board addressing
+
+ ROM_REGION( 0x4000, "speech:data", 0 )
ROM_LOAD( "970c.speech-u6", 0x0000, 0x1000, CRC(979d8535) SHA1(1ed097e563319ca6d2b7df9875ce7ee921eae468) )
ROM_LOAD( "971c.speech-u5", 0x1000, 0x1000, CRC(022dbd32) SHA1(4e0504b5ccc28094078912673c49571cf83804ab) )
ROM_LOAD( "972c.speech-u4", 0x2000, 0x1000, CRC(fad9346d) SHA1(784e5ab0fb00235cfd733c502baf23960923504f) )
- ROM_REGION( 0x0440, "proms", 0 )
- ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) /* sine table */
- ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* CPU board addressing */
- ROM_LOAD( "6331.speech-u30", 0x0420, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* speech board addressing */
+ ROM_REGION( 0x0420, "proms", 0 )
+ ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) // sine table
+ ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) // CPU board addressing
ROM_END
-ROM_START( spacfurya ) /* Revision A */
+ROM_START( spacfurya ) // Revision A
ROM_REGION( 0xc000, "maincpu", 0 )
ROM_LOAD( "969a.cpu-u25", 0x0000, 0x0800, CRC(896a615c) SHA1(542386196eca9fd822e36508e173201ee8a962ed) )
ROM_LOAD( "960a.prom-u1", 0x0800, 0x0800, CRC(e1ea7964) SHA1(9c84c525973fcf1437b062d98195272723249d02) )
@@ -1134,21 +1116,23 @@ ROM_START( spacfurya ) /* Revision A */
ROM_LOAD( "967a.prom-u8", 0x4000, 0x0800, CRC(d60f667d) SHA1(821271ec1918e22ed29a5b1f4b0182765ef5ba10) )
ROM_LOAD( "968a.prom-u9", 0x4800, 0x0800, CRC(aea85b6a) SHA1(8778ff0be34cd4fd5b8f6f76c64bfca68d4d240e) )
- ROM_REGION( 0x0800, "audiocpu", 0 )
+ ROM_REGION( 0x0800, "speech:cpu", 0 )
ROM_LOAD( "808a.speech-u7", 0x0000, 0x0800, CRC(5988c767) SHA1(3b91a8cd46aa7e714028cc40f700fea32287afb1) )
- ROM_REGION( 0x4000, SEGASND_SEGASPEECH_REGION, 0 )
+ ROM_REGION( 0x0020, "speech:proms", 0 )
+ ROM_LOAD( "6331.speech-u30", 0x0000, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) // speech board addressing
+
+ ROM_REGION( 0x4000, "speech:data", 0 )
ROM_LOAD( "970.speech-u6", 0x0000, 0x1000, CRC(f3b47b36) SHA1(6ae0b627349664140a7f70799645b368e452d69c) )
ROM_LOAD( "971.speech-u5", 0x1000, 0x1000, CRC(e72bbe88) SHA1(efadf8aa448c289cf4d0cf1831255b9ac60820f2) )
ROM_LOAD( "972.speech-u4", 0x2000, 0x1000, CRC(8b3da539) SHA1(3a0c4af96a2116fc668a340534582776b2018663) )
- ROM_REGION( 0x0440, "proms", 0 )
- ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) /* sine table */
- ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* CPU board addressing */
- ROM_LOAD( "6331.speech-u30", 0x0420, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* speech board addressing */
+ ROM_REGION( 0x0420, "proms", 0 )
+ ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) // sine table
+ ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) // CPU board addressing
ROM_END
-ROM_START( spacfuryb ) /* Revision B */
+ROM_START( spacfuryb ) // Revision B
ROM_REGION( 0xc000, "maincpu", 0 )
ROM_LOAD( "969a.cpu-u25", 0x0000, 0x0800, CRC(896a615c) SHA1(542386196eca9fd822e36508e173201ee8a962ed) )
ROM_LOAD( "960b.prom-u1", 0x0800, 0x0800, CRC(8a99b63f) SHA1(4b9ec152e0fad50afeea11f5d61331f3211da606) )
@@ -1161,18 +1145,20 @@ ROM_START( spacfuryb ) /* Revision B */
ROM_LOAD( "967b.prom-u8", 0x4000, 0x0800, CRC(82b5768d) SHA1(823d8c0a537bad62e8186f88f8d02a0f3dc6da0f) )
ROM_LOAD( "968b.prom-u9", 0x4800, 0x0800, CRC(fea68f02) SHA1(83bef40dfaac014b7929239d81075335ff8fd506) )
- ROM_REGION( 0x0800, "audiocpu", 0 )
+ ROM_REGION( 0x0800, "speech:cpu", 0 )
ROM_LOAD( "808a.speech-u7", 0x0000, 0x0800, CRC(5988c767) SHA1(3b91a8cd46aa7e714028cc40f700fea32287afb1) )
- ROM_REGION( 0x4000, SEGASND_SEGASPEECH_REGION, 0 )
+ ROM_REGION( 0x0020, "speech:proms", 0 )
+ ROM_LOAD( "6331.speech-u30", 0x0000, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) // speech board addressing
+
+ ROM_REGION( 0x4000, "speech:data", 0 )
ROM_LOAD( "970.speech-u6", 0x0000, 0x1000, CRC(f3b47b36) SHA1(6ae0b627349664140a7f70799645b368e452d69c) )
ROM_LOAD( "971.speech-u5", 0x1000, 0x1000, CRC(e72bbe88) SHA1(efadf8aa448c289cf4d0cf1831255b9ac60820f2) )
ROM_LOAD( "972.speech-u4", 0x2000, 0x1000, CRC(8b3da539) SHA1(3a0c4af96a2116fc668a340534582776b2018663) )
- ROM_REGION( 0x0440, "proms", 0 )
- ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) /* sine table */
- ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* CPU board addressing */
- ROM_LOAD( "6331.speech-u30", 0x0420, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* speech board addressing */
+ ROM_REGION( 0x0420, "proms", 0 )
+ ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) // sine table
+ ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) // CPU board addressing
ROM_END
@@ -1201,18 +1187,20 @@ ROM_START( zektor )
ROM_LOAD( "1605.prom-u20", 0xa000, 0x0800, CRC(e27d7144) SHA1(5b82fda797d86e11882d1f9738a59092c5e3e7d8) )
ROM_LOAD( "1606.prom-u21", 0xa800, 0x0800, CRC(7965f636) SHA1(5c8720beedab4979a813ce7f0e8961c863973ff7) )
- ROM_REGION( 0x0800, "audiocpu", 0 )
+ ROM_REGION( 0x0800, "speech:cpu", 0 )
ROM_LOAD( "1607.speech-u7", 0x0000, 0x0800, CRC(b779884b) SHA1(ac07e99717a1f51b79f3e43a5d873ebfa0559320) )
- ROM_REGION( 0x4000, SEGASND_SEGASPEECH_REGION, 0 )
+ ROM_REGION( 0x0020, "speech:proms", 0 )
+ ROM_LOAD( "6331.speech-u30", 0x0000, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) // speech board addressing
+
+ ROM_REGION( 0x4000, "speech:data", 0 )
ROM_LOAD( "1608.speech-u6", 0x0000, 0x1000, CRC(637e2b13) SHA1(8a470f9a8a722f7ced340c4d32b4cf6f05b3e848) )
ROM_LOAD( "1609.speech-u5", 0x1000, 0x1000, CRC(675ee8e5) SHA1(e314482028b8925ad02e833a1d22224533d0a683) )
ROM_LOAD( "1610.speech-u4", 0x2000, 0x1000, CRC(2915c7bd) SHA1(3ed98747b5237aa1b3bab6866292370dc2c7655a) )
- ROM_REGION( 0x0440, "proms", 0 )
- ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) /* sine table */
- ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* CPU board addressing */
- ROM_LOAD( "6331.speech-u30", 0x0420, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* speech board addressing */
+ ROM_REGION( 0x0420, "proms", 0 )
+ ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) // sine table
+ ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) // CPU board addressing
ROM_END
@@ -1242,8 +1230,8 @@ ROM_START( tacscan )
ROM_LOAD( "1710a.prom-u21", 0xa800, 0x0800, CRC(6203be22) SHA1(89731c7c88d0125a11368d707f566eb53c783266) )
ROM_REGION( 0x0420, "proms", 0 )
- ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) /* sine table */
- ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* CPU board addressing */
+ ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) // sine table
+ ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) // CPU board addressing
ROM_END
@@ -1274,17 +1262,19 @@ ROM_START( startrek )
ROM_LOAD( "1869.prom-u22", 0xb000, 0x0800, CRC(e5663070) SHA1(735944c2b924964f72f3bb3d251a35ea2aef3d15) )
ROM_LOAD( "1870.prom-u23", 0xb800, 0x0800, CRC(4340616d) SHA1(e93686a29377933332523425532d102e30211111) )
- ROM_REGION( 0x0800, "audiocpu", 0 )
+ ROM_REGION( 0x0800, "speech:cpu", 0 )
ROM_LOAD( "1670.speech-u7", 0x0000, 0x0800, CRC(b779884b) SHA1(ac07e99717a1f51b79f3e43a5d873ebfa0559320) )
- ROM_REGION( 0x4000, SEGASND_SEGASPEECH_REGION, 0 )
+ ROM_REGION( 0x0020, "speech:proms", 0 )
+ ROM_LOAD( "6331.speech-u30", 0x0000, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) // speech board addressing
+
+ ROM_REGION( 0x4000, "speech:data", 0 )
ROM_LOAD( "1871.speech-u6", 0x0000, 0x1000, CRC(03713920) SHA1(25a0158cab9983248e91133f96d1849c9e9bcbd2) )
ROM_LOAD( "1872.speech-u5", 0x1000, 0x1000, CRC(ebb5c3a9) SHA1(533b6f0499b311f561cf7aba14a7f48ca7c47321) )
- ROM_REGION( 0x0440, "proms", 0 )
- ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) /* sine table */
- ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) /* CPU board addressing */
- ROM_LOAD( "6331.speech-u30", 0x0420, 0x0020, CRC(adcb81d0) SHA1(74b0efc7e8362b0c98e54a6107981cff656d87e1) ) /* speech board addressing */
+ ROM_REGION( 0x0420, "proms", 0 )
+ ROM_LOAD( "s-c.xyt-u39", 0x0000, 0x0400, CRC(56484d19) SHA1(61f43126fdcfc230638ed47085ae037a098e6781) ) // sine table
+ ROM_LOAD( "pr-82.cpu-u15", 0x0400, 0x0020, CRC(c609b79e) SHA1(49dbcbb607079a182d7eb396c0da097166ea91c9) ) // CPU board addressing
ROM_END
@@ -1295,31 +1285,59 @@ ROM_END
*
*************************************/
+void segag80v_state::init_waitstates()
+{
+ address_space &pgmspace = m_maincpu->space(AS_PROGRAM);
+ address_space &opspace = m_maincpu->space(AS_OPCODES);
+
+ pgmspace.install_read_tap(0x0000, 0xffff, "program_waitstate_r",[this](offs_t offset, u8 &data, u8 mem_mask)
+ {
+ if (!machine().side_effects_disabled())
+ m_maincpu->adjust_icount(-WAIT_STATES);
+ return data;
+ });
+ pgmspace.install_write_tap(0x0000, 0xffff, "program_waitstate_w",[this](offs_t offset, u8 &data, u8 mem_mask)
+ {
+ if (!machine().side_effects_disabled())
+ m_maincpu->adjust_icount(-WAIT_STATES);
+ return data;
+ });
+
+ opspace.install_read_tap(0x0000, 0xffff, "opcodes_waitstate_r",[this](offs_t offset, u8 &data, u8 mem_mask)
+ {
+ if (!machine().side_effects_disabled())
+ m_maincpu->adjust_icount(-WAIT_STATES);
+ return data;
+ });
+}
+
void segag80v_state::init_elim2()
{
+ init_waitstates();
+
address_space &iospace = m_maincpu->space(AS_IO);
- /* configure security */
+ // configure security
m_decrypt = segag80_security(70);
- /* configure sound */
- iospace.install_write_handler(0x3e, 0x3e, write8smo_delegate(*this, FUNC(segag80v_state::elim1_sh_w)));
- iospace.install_write_handler(0x3f, 0x3f, write8smo_delegate(*this, FUNC(segag80v_state::elim2_sh_w)));
+ // configure sound
+ iospace.install_write_handler(0x3e, 0x3f, write8sm_delegate(*m_g80_audio, FUNC(segag80_audio_device::write)));
}
void segag80v_state::init_elim4()
{
+ init_waitstates();
+
address_space &iospace = m_maincpu->space(AS_IO);
- /* configure security */
+ // configure security
m_decrypt = segag80_security(76);
- /* configure sound */
- iospace.install_write_handler(0x3e, 0x3e, write8smo_delegate(*this, FUNC(segag80v_state::elim1_sh_w)));
- iospace.install_write_handler(0x3f, 0x3f, write8smo_delegate(*this, FUNC(segag80v_state::elim2_sh_w)));
+ // configure sound
+ iospace.install_write_handler(0x3e, 0x3f, write8sm_delegate(*m_g80_audio, FUNC(segag80_audio_device::write)));
- /* configure inputs */
+ // configure inputs
iospace.install_write_handler(0xf8, 0xf8, write8smo_delegate(*this, FUNC(segag80v_state::spinner_select_w)));
iospace.install_read_handler(0xfc, 0xfc, read8smo_delegate(*this, FUNC(segag80v_state::elim4_input_r)));
}
@@ -1327,34 +1345,36 @@ void segag80v_state::init_elim4()
void segag80v_state::init_spacfury()
{
+ init_waitstates();
+
address_space &iospace = m_maincpu->space(AS_IO);
- /* configure security */
+ // configure security
m_decrypt = segag80_security(64);
- /* configure sound */
- iospace.install_write_handler(0x38, 0x38, write8smo_delegate(*m_speech, FUNC(speech_sound_device::data_w)));
- iospace.install_write_handler(0x3b, 0x3b, write8smo_delegate(*m_speech, FUNC(speech_sound_device::control_w)));
- iospace.install_write_handler(0x3e, 0x3e, write8smo_delegate(*this, FUNC(segag80v_state::spacfury1_sh_w)));
- iospace.install_write_handler(0x3f, 0x3f, write8smo_delegate(*this, FUNC(segag80v_state::spacfury2_sh_w)));
+ // configure sound
+ iospace.install_write_handler(0x38, 0x38, write8smo_delegate(*m_speech, FUNC(sega_speech_device::data_w)));
+ iospace.install_write_handler(0x3b, 0x3b, write8smo_delegate(*m_speech, FUNC(sega_speech_device::control_w)));
+ iospace.install_write_handler(0x3e, 0x3f, write8sm_delegate(*m_g80_audio, FUNC(segag80_audio_device::write)));
}
void segag80v_state::init_zektor()
{
+ init_waitstates();
+
address_space &iospace = m_maincpu->space(AS_IO);
- /* configure security */
+ // configure security
m_decrypt = segag80_security(82);
- /* configure sound */
- iospace.install_write_handler(0x38, 0x38, write8smo_delegate(*m_speech, FUNC(speech_sound_device::data_w)));
- iospace.install_write_handler(0x3b, 0x3b, write8smo_delegate(*m_speech, FUNC(speech_sound_device::control_w)));
- iospace.install_write_handler(0x3c, 0x3d, write8sm_delegate(*m_aysnd, FUNC(ay8912_device::address_data_w)));
- iospace.install_write_handler(0x3e, 0x3e, write8smo_delegate(*this, FUNC(segag80v_state::zektor1_sh_w)));
- iospace.install_write_handler(0x3f, 0x3f, write8smo_delegate(*this, FUNC(segag80v_state::zektor2_sh_w)));
+ // configure sound
+ iospace.install_write_handler(0x38, 0x38, write8smo_delegate(*m_speech, FUNC(sega_speech_device::data_w)));
+ iospace.install_write_handler(0x3b, 0x3b, write8smo_delegate(*m_speech, FUNC(sega_speech_device::control_w)));
+ iospace.install_write_handler(0x3c, 0x3d, write8sm_delegate(*m_g80_audio, FUNC(segag80_audio_device::write_ay)));
+ iospace.install_write_handler(0x3e, 0x3f, write8sm_delegate(*m_g80_audio, FUNC(segag80_audio_device::write)));
- /* configure inputs */
+ // configure inputs
iospace.install_write_handler(0xf8, 0xf8, write8smo_delegate(*this, FUNC(segag80v_state::spinner_select_w)));
iospace.install_read_handler(0xfc, 0xfc, read8smo_delegate(*this, FUNC(segag80v_state::spinner_input_r)));
}
@@ -1362,18 +1382,20 @@ void segag80v_state::init_zektor()
void segag80v_state::init_tacscan()
{
+ init_waitstates();
+
address_space &pgmspace = m_maincpu->space(AS_PROGRAM);
address_space &iospace = m_maincpu->space(AS_IO);
- /* configure security */
+ // configure security
m_decrypt = segag80_security(76);
- /* configure sound */
+ // configure sound
iospace.install_readwrite_handler(0x3f, 0x3f, read8smo_delegate(*m_usb, FUNC(usb_sound_device::status_r)), write8smo_delegate(*m_usb, FUNC(usb_sound_device::data_w)));
pgmspace.install_read_handler(0xd000, 0xdfff, read8sm_delegate(*m_usb, FUNC(usb_sound_device::ram_r)));
pgmspace.install_write_handler(0xd000, 0xdfff, write8sm_delegate(*this, FUNC(segag80v_state::usb_ram_w)));
- /* configure inputs */
+ // configure inputs
iospace.install_write_handler(0xf8, 0xf8, write8smo_delegate(*this, FUNC(segag80v_state::spinner_select_w)));
iospace.install_read_handler(0xfc, 0xfc, read8smo_delegate(*this, FUNC(segag80v_state::spinner_input_r)));
}
@@ -1381,21 +1403,23 @@ void segag80v_state::init_tacscan()
void segag80v_state::init_startrek()
{
+ init_waitstates();
+
address_space &pgmspace = m_maincpu->space(AS_PROGRAM);
address_space &iospace = m_maincpu->space(AS_IO);
- /* configure security */
+ // configure security
m_decrypt = segag80_security(64);
- /* configure sound */
- iospace.install_write_handler(0x38, 0x38, write8smo_delegate(*m_speech, FUNC(speech_sound_device::data_w)));
- iospace.install_write_handler(0x3b, 0x3b, write8smo_delegate(*m_speech, FUNC(speech_sound_device::control_w)));
+ // configure sound
+ iospace.install_write_handler(0x38, 0x38, write8smo_delegate(*m_speech, FUNC(sega_speech_device::data_w)));
+ iospace.install_write_handler(0x3b, 0x3b, write8smo_delegate(*m_speech, FUNC(sega_speech_device::control_w)));
iospace.install_readwrite_handler(0x3f, 0x3f, read8smo_delegate(*m_usb, FUNC(usb_sound_device::status_r)), write8smo_delegate(*m_usb, FUNC(usb_sound_device::data_w)));
pgmspace.install_read_handler(0xd000, 0xdfff, read8sm_delegate(*m_usb, FUNC(usb_sound_device::ram_r)));
pgmspace.install_write_handler(0xd000, 0xdfff, write8sm_delegate(*this, FUNC(segag80v_state::usb_ram_w)));
- /* configure inputs */
+ // configure inputs
iospace.install_write_handler(0xf8, 0xf8, write8smo_delegate(*this, FUNC(segag80v_state::spinner_select_w)));
iospace.install_read_handler(0xfc, 0xfc, read8smo_delegate(*this, FUNC(segag80v_state::spinner_input_r)));
}
@@ -1409,14 +1433,14 @@ void segag80v_state::init_startrek()
*************************************/
// YEAR, NAME, PARENT, MACHINE, INPUT, STATE INIT, MONITOR, COMPANY, FULLNAME,FLAGS
-GAME( 1981, elim2, 0, elim2, elim2, segag80v_state, init_elim2, ORIENTATION_FLIP_Y, "Gremlin", "Eliminator (2 Players, set 1)", MACHINE_IMPERFECT_SOUND )
-GAME( 1981, elim2a, elim2, elim2, elim2, segag80v_state, init_elim2, ORIENTATION_FLIP_Y, "Gremlin", "Eliminator (2 Players, set 2)", MACHINE_IMPERFECT_SOUND )
-GAME( 1981, elim2c, elim2, elim2, elim2c, segag80v_state, init_elim2, ORIENTATION_FLIP_Y, "Gremlin", "Eliminator (2 Players, cocktail)", MACHINE_IMPERFECT_SOUND )
-GAME( 1981, elim4, elim2, elim2, elim4, segag80v_state, init_elim4, ORIENTATION_FLIP_Y, "Gremlin", "Eliminator (4 Players)", MACHINE_IMPERFECT_SOUND )
-GAME( 1981, elim4p, elim2, elim2, elim4, segag80v_state, init_elim4, ORIENTATION_FLIP_Y, "Gremlin", "Eliminator (4 Players, prototype)", MACHINE_IMPERFECT_SOUND )
-GAME( 1981, spacfury, 0, spacfury, spacfury, segag80v_state, init_spacfury, ORIENTATION_FLIP_Y, "Sega", "Space Fury (revision C)", MACHINE_IMPERFECT_SOUND )
-GAME( 1981, spacfurya, spacfury, spacfury, spacfury, segag80v_state, init_spacfury, ORIENTATION_FLIP_Y, "Sega", "Space Fury (revision A)", MACHINE_IMPERFECT_SOUND )
-GAME( 1981, spacfuryb, spacfury, spacfury, spacfury, segag80v_state, init_spacfury, ORIENTATION_FLIP_Y, "Sega", "Space Fury (revision B)", MACHINE_IMPERFECT_SOUND )
-GAME( 1982, zektor, 0, zektor, zektor, segag80v_state, init_zektor, ORIENTATION_FLIP_Y, "Sega", "Zektor (revision B)", MACHINE_IMPERFECT_SOUND )
-GAME( 1982, tacscan, 0, tacscan, tacscan, segag80v_state, init_tacscan, ORIENTATION_FLIP_X ^ ROT270, "Sega", "Tac/Scan", MACHINE_IMPERFECT_SOUND )
-GAME( 1982, startrek, 0, startrek, startrek, segag80v_state, init_startrek, ORIENTATION_FLIP_Y, "Sega", "Star Trek", MACHINE_IMPERFECT_SOUND )
+GAME( 1981, elim2, 0, elim2, elim2, segag80v_state, init_elim2, ORIENTATION_FLIP_Y, "Gremlin", "Eliminator (2 Players, set 1)", 0 )
+GAME( 1981, elim2a, elim2, elim2, elim2, segag80v_state, init_elim2, ORIENTATION_FLIP_Y, "Gremlin", "Eliminator (2 Players, set 2)", 0 )
+GAME( 1981, elim2c, elim2, elim2, elim2c, segag80v_state, init_elim2, ORIENTATION_FLIP_Y, "Gremlin", "Eliminator (2 Players, cocktail)", 0 )
+GAME( 1981, elim4, elim2, elim2, elim4, segag80v_state, init_elim4, ORIENTATION_FLIP_Y, "Gremlin", "Eliminator (4 Players)", 0 )
+GAME( 1981, elim4p, elim2, elim2, elim4, segag80v_state, init_elim4, ORIENTATION_FLIP_Y, "Gremlin", "Eliminator (4 Players, prototype)", 0 )
+GAME( 1981, spacfury, 0, spacfury, spacfury, segag80v_state, init_spacfury, ORIENTATION_FLIP_Y, "Sega", "Space Fury (revision C)", 0 )
+GAME( 1981, spacfurya, spacfury, spacfury, spacfury, segag80v_state, init_spacfury, ORIENTATION_FLIP_Y, "Sega", "Space Fury (revision A)", 0 )
+GAME( 1981, spacfuryb, spacfury, spacfury, spacfury, segag80v_state, init_spacfury, ORIENTATION_FLIP_Y, "Sega", "Space Fury (revision B)", 0 )
+GAME( 1982, zektor, 0, zektor, zektor, segag80v_state, init_zektor, ORIENTATION_FLIP_Y, "Sega", "Zektor (revision B)", 0 )
+GAME( 1982, tacscan, 0, tacscan, tacscan, segag80v_state, init_tacscan, ORIENTATION_FLIP_X ^ ROT270, "Sega", "Tac/Scan", 0 )
+GAME( 1982, startrek, 0, startrek, startrek, segag80v_state, init_startrek, ORIENTATION_FLIP_Y, "Sega", "Star Trek", 0 )
diff --git a/src/mame/drivers/zaxxon.cpp b/src/mame/drivers/zaxxon.cpp
index a6edd92174b..43436590c13 100644
--- a/src/mame/drivers/zaxxon.cpp
+++ b/src/mame/drivers/zaxxon.cpp
@@ -255,7 +255,7 @@
#include "emu.h"
#include "includes/zaxxon.h"
-#include "audio/segasnd.h"
+#include "audio/segausb.h"
#include "cpu/z80/z80.h"
#include "machine/gen_latch.h"
diff --git a/src/mame/includes/segag80r.h b/src/mame/includes/segag80r.h
index 9e54a676882..a4c996149fd 100644
--- a/src/mame/includes/segag80r.h
+++ b/src/mame/includes/segag80r.h
@@ -10,8 +10,10 @@
#pragma once
+#include "audio/segag80.h"
#include "audio/segag80r.h"
-#include "audio/segasnd.h"
+#include "audio/segaspeech.h"
+#include "audio/segausb.h"
#include "machine/i8255.h"
#include "machine/segag80.h"
#include "sound/samples.h"
@@ -23,11 +25,11 @@
class sega005_sound_device;
-class segag80r_state : public segag80snd_common
+class segag80r_state : public driver_device
{
public:
segag80r_state(const machine_config &mconfig, device_type type, const char *tag) :
- segag80snd_common(mconfig, type, tag),
+ driver_device(mconfig, type, tag),
m_mainram(*this, "mainram"),
m_videoram(*this, "videoram"),
m_sn1(*this, "sn1"),
@@ -36,7 +38,8 @@ public:
m_audiocpu(*this, "audiocpu"),
m_soundbrd(*this, "soundbrd"),
m_samples(*this, "samples"),
- m_speech(*this, "segaspeech"),
+ m_speech(*this, "speech"),
+ m_g80_audio(*this, "g80sound"),
m_usbsnd(*this, "usbsnd"),
m_005snd(*this, "005"),
m_gfxdecode(*this, "gfxdecode"),
@@ -53,11 +56,11 @@ public:
void monster2(machine_config &config);
void sega005(machine_config &config);
void spaceod(machine_config &config);
- void astrob_sound_board(machine_config &config);
void sega005_sound_board(machine_config &config);
void spaceod_sound_board(machine_config &config);
void monsterb_sound_board(machine_config &config);
+ void init_waitstates();
void init_spaceod();
void init_sindbadm();
void init_pignewt();
@@ -91,7 +94,8 @@ private:
optional_device<cpu_device> m_audiocpu;
optional_device<monsterb_sound_device> m_soundbrd;
optional_device<samples_device> m_samples;
- optional_device<speech_sound_device> m_speech;
+ optional_device<sega_speech_device> m_speech;
+ optional_device<segag80_audio_device> m_g80_audio;
optional_device<usb_sound_device> m_usbsnd;
optional_device<sega005_sound_device> m_005snd;
required_device<gfxdecode_device> m_gfxdecode;
@@ -147,7 +151,6 @@ private:
void pignewt_back_port_w(offs_t offset, uint8_t data);
void sindbadm_videoram_w(offs_t offset, uint8_t data);
void sindbadm_back_port_w(offs_t offset, uint8_t data);
- void astrob_sound_w(offs_t offset, uint8_t data);
void spaceod_sound_w(offs_t offset, uint8_t data);
void usb_ram_w(offs_t offset, uint8_t data);
diff --git a/src/mame/includes/segag80v.h b/src/mame/includes/segag80v.h
index dd247ac859c..7f5fc5d007f 100644
--- a/src/mame/includes/segag80v.h
+++ b/src/mame/includes/segag80v.h
@@ -6,7 +6,10 @@
*************************************************************************/
-#include "audio/segasnd.h"
+#include "audio/segaspeech.h"
+#include "audio/segausb.h"
+#include "audio/segag80.h"
+#include "cpu/z80/z80.h"
#include "machine/segag80.h"
#include "sound/ay8910.h"
#include "sound/samples.h"
@@ -14,20 +17,45 @@
#include "screen.h"
-class segag80v_state : public segag80snd_common
+#define CPU_CLOCK 8000000 /* not used when video boards are connected */
+#define VIDEO_CLOCK 15468480
+
+class segag80v_state : public driver_device
{
public:
- segag80v_state(const machine_config &mconfig, device_type type, const char *tag)
- : segag80snd_common(mconfig, type, tag),
+ segag80v_state(const machine_config &mconfig, device_type type, const char *tag) :
+ driver_device(mconfig, type, tag),
+ m_mainrom(*this, "maincpu"),
m_mainram(*this, "mainram"),
m_vectorram(*this, "vectorram"),
m_maincpu(*this, "maincpu"),
m_samples(*this, "samples"),
- m_speech(*this, "segaspeech"),
+ m_speech(*this, "speech"),
m_usb(*this, "usbsnd"),
+ m_g80_audio(*this, "g80sound"),
m_aysnd(*this, "aysnd"),
m_vector(*this, "vector"),
- m_screen(*this, "screen")
+ m_screen(*this, "screen"),
+ m_d7d6(*this, "D7D6"),
+ m_d5d4(*this, "D5D4"),
+ m_d3d2(*this, "D3D2"),
+ m_d1d0(*this, "D1D0"),
+ m_fc(*this, "FC"),
+ m_coins(*this, "COINS"),
+ m_spinner(*this, "SPINNER"),
+ m_mult_data{0,0},
+ m_mult_result(0),
+ m_spinner_select(0),
+ m_spinner_sign(0),
+ m_spinner_count(0),
+ m_coin_ff_state(0),
+ m_coin_last_state(0),
+ m_edgint_ff_state(0),
+ m_scrambled_write_pc(0),
+ m_decrypt(nullptr),
+ m_min_x(0),
+ m_min_y(0),
+ m_draw_end_time(attotime::zero)
{ }
void g80v_base(machine_config &config);
@@ -37,6 +65,7 @@ public:
void zektor(machine_config &config);
void spacfury(machine_config &config);
+ void init_waitstates();
void init_zektor();
void init_startrek();
void init_elim4();
@@ -44,59 +73,89 @@ public:
void init_tacscan();
void init_spacfury();
- DECLARE_INPUT_CHANGED_MEMBER(service_switch);
DECLARE_READ_LINE_MEMBER(elim4_joint_coin_r);
+ DECLARE_READ_LINE_MEMBER(draw_r);
+ DECLARE_WRITE_LINE_MEMBER(service_switch_w);
+ DECLARE_WRITE_LINE_MEMBER(irq_ack_w);
+
+ template<int _Index>
+ DECLARE_WRITE_LINE_MEMBER( coin_w )
+ {
+ const u8 mask = 1 << _Index;
+
+ if (state == 0 && (m_coin_last_state & mask) != 0)
+ m_coin_ff_state |= mask;
+ else
+ m_coin_ff_state &= ~mask;
+
+ if (state)
+ m_coin_last_state |= mask;
+ else
+ m_coin_last_state &= ~mask;
+
+ update_int();
+ }
private:
- required_shared_ptr<uint8_t> m_mainram;
- required_shared_ptr<uint8_t> m_vectorram;
+ required_memory_region m_mainrom;
+ required_shared_ptr<u8> m_mainram;
+ required_shared_ptr<u8> m_vectorram;
- required_device<cpu_device> m_maincpu;
+ required_device<z80_device> m_maincpu;
optional_device<samples_device> m_samples;
- optional_device<speech_sound_device> m_speech;
+ optional_device<sega_speech_device> m_speech;
optional_device<usb_sound_device> m_usb;
+ optional_device<segag80_audio_device> m_g80_audio;
optional_device<ay8912_device> m_aysnd;
required_device<vector_device> m_vector;
required_device<screen_device> m_screen;
-
- uint8_t m_mult_data[2];
- uint16_t m_mult_result;
- uint8_t m_spinner_select;
- uint8_t m_spinner_sign;
- uint8_t m_spinner_count;
+ required_ioport m_d7d6;
+ required_ioport m_d5d4;
+ required_ioport m_d3d2;
+ required_ioport m_d1d0;
+ required_ioport m_fc;
+ optional_ioport m_coins;
+ optional_ioport m_spinner;
+
+ u8 m_mult_data[2];
+ u16 m_mult_result;
+ u8 m_spinner_select;
+ u8 m_spinner_sign;
+ u8 m_spinner_count;
+ u8 m_coin_ff_state;
+ u8 m_coin_last_state;
+ u8 m_edgint_ff_state;
offs_t m_scrambled_write_pc;
segag80_decrypt_func m_decrypt;
int m_min_x;
int m_min_y;
- uint8_t g80v_opcode_r(offs_t offset);
- void mainram_w(offs_t offset, uint8_t data);
- void vectorram_w(offs_t offset, uint8_t data);
- uint8_t mangled_ports_r(offs_t offset);
- void spinner_select_w(uint8_t data);
- uint8_t spinner_input_r();
- uint8_t elim4_input_r();
- void multiply_w(offs_t offset, uint8_t data);
- uint8_t multiply_r();
- void coin_count_w(uint8_t data);
- void unknown_w(uint8_t data);
-
- void elim1_sh_w(uint8_t data);
- void elim2_sh_w(uint8_t data);
- void zektor1_sh_w(uint8_t data);
- void zektor2_sh_w(uint8_t data);
- void spacfury1_sh_w(uint8_t data);
- void spacfury2_sh_w(uint8_t data);
-
- void usb_ram_w(offs_t offset, uint8_t data);
+ attotime m_draw_end_time;
+
+ u8 opcode_r(offs_t offset);
+ u8 mainrom_r(offs_t offset);
+ void mainram_w(offs_t offset, u8 data);
+ void vectorram_w(offs_t offset, u8 data);
+ u8 mangled_ports_r(offs_t offset);
+ void spinner_select_w(u8 data);
+ u8 spinner_input_r();
+ u8 elim4_input_r();
+ void multiply_w(offs_t offset, u8 data);
+ u8 multiply_r();
+ void coin_count_w(u8 data);
+ void unknown_w(u8 data);
+ void update_int();
+ void vblank_callback(screen_device &screen, bool state);
+
+ void usb_ram_w(offs_t offset, u8 data);
virtual void machine_start() override;
virtual void video_start() override;
uint32_t screen_update_segag80v(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
- inline bool adjust_xy(int rawx, int rawy, int *outx, int *outy);
+ inline bool adjust_xy(int rawx, int rawy, int &outx, int &outy);
void sega_generate_vector_list();
offs_t decrypt_offset(offs_t offset);
- inline uint8_t demangle(uint8_t d7d6, uint8_t d5d4, uint8_t d3d2, uint8_t d1d0);
+ inline u8 demangle(u8 d7d6, u8 d5d4, u8 d3d2, u8 d1d0);
void main_map(address_map &map);
void opcodes_map(address_map &map);
diff --git a/src/mame/nl.lst b/src/mame/nl.lst
index a55bc5f1fcb..ce1ddf052ff 100644
--- a/src/mame/nl.lst
+++ b/src/mame/nl.lst
@@ -335,6 +335,49 @@ popeyej
popeyejo
popeyehs
+@source:segag80r.cpp
+005 // (c) 1981
+astrob // (c) 1981
+astrob1 // (c) 1981
+astrob2 // (c) 1981
+astrob2a // (c) 1981
+astrob2b // (c) 1981
+astrobg // (c) 1981
+monsterb // (c) 1982
+monsterb2 // (c) 1982
+pignewt // (c) 1983
+pignewta // (c) 1983
+sindbadm // 834-5244 (c) 1983 Sega
+spaceod // (c) 1981
+spaceod2 // (c) 1981
+
+@source:segag80v.cpp
+elim2 // (c) 1981 Gremlin
+elim2a // (c) 1981 Gremlin
+elim2c // (c) 1981 Gremlin
+elim4 // (c) 1981 Gremlin
+elim4p // (c) 1981 Gremlin
+spacfury // (c) 1981
+spacfurya // no copyright notice
+spacfuryb // no copyright notice
+startrek // (c) 1982
+tacscan // (c) 1982
+zektor // (c) 1982
+
+@source:zaxxon.cpp
+congo // 605-5167 (c) 1983 (2 board stack)
+congoa // 605-5167 (c) 1983 (3 board stack)
+futspy // (c) 1984
+ixion // (c) 1983
+razmataz // modified 834-0213, 834-0214 (c) 1983
+szaxxon // (c) 1982
+tiptop // 605-5167 (c) 1983 (3 board stack)
+zaxxon // (c) 1982
+zaxxon2 // (c) 1982
+zaxxon3 // (c) 1982
+zaxxonb // bootleg
+zaxxonj // (c) 1982
+
@source:segas16b.cpp
aceattac // (c) 1988 (FD1094)
//afightere
diff --git a/src/mame/video/segag80v.cpp b/src/mame/video/segag80v.cpp
index 110930e5973..bc126f72fe4 100644
--- a/src/mame/video/segag80v.cpp
+++ b/src/mame/video/segag80v.cpp
@@ -9,13 +9,17 @@
#include "emu.h"
#include "includes/segag80v.h"
-#define VECTOR_CLOCK 15468480 /* master clock */
-#define U34_CLOCK (VECTOR_CLOCK/3) /* clock for interrupt chain */
-#define VCL_CLOCK (U34_CLOCK/2) /* clock for vector generator */
-#define U51_CLOCK (VCL_CLOCK/16) /* clock for phase generator */
-#define IRQ_CLOCK (U34_CLOCK/0x1f788) /* 40Hz interrupt */
+#define VECTOR_CLOCK 15468480 // master clock
+#define U34_CLOCK (VECTOR_CLOCK/3) // clock for interrupt chain
+#define VCL_CLOCK (U34_CLOCK/2) // clock for vector generator
+#define U51_CLOCK (VCL_CLOCK/16) // clock for phase generator
+#define IRQ_CLOCK (U34_CLOCK/0x1f788) // 40Hz interrupt
+static constexpr attoseconds_t VCL_ATTOS = HZ_TO_ATTOSECONDS(VCL_CLOCK);
+static constexpr attoseconds_t U51_ATTOS = HZ_TO_ATTOSECONDS(U51_CLOCK);
+static constexpr attoseconds_t IRQ_ATTOS = HZ_TO_ATTOSECONDS(IRQ_CLOCK);
+
/*
@@ -73,247 +77,239 @@
A1-A8 = sum of VEC angle and SYM angle (low 8 bits)
A9 = sum of bit 8 of VEC angle and SYM angle, plus 1 for phase 13
-
*/
-inline bool segag80v_state::adjust_xy(int rawx, int rawy, int *outx, int *outy)
+
+inline bool segag80v_state::adjust_xy(int rawx, int rawy, int &outx, int &outy)
{
bool clipped = false;
- /* first apply the XOR at 0x200 */
- *outx = (rawx & 0x7ff) ^ 0x200;
- *outy = (rawy & 0x7ff) ^ 0x200;
+ // first apply the XOR at 0x200
+ outx = (rawx & 0x7ff) ^ 0x200;
+ outy = (rawy & 0x7ff) ^ 0x200;
- /* apply clipping logic to X */
- if ((*outx & 0x600) == 0x200)
- *outx = 0x000, clipped = true;
- else if ((*outx & 0x600) == 0x400)
- *outx = 0x3ff, clipped = true;
+ // apply clipping logic to X
+ if ((outx & 0x600) == 0x200)
+ outx = 0x000, clipped = true;
+ else if ((outx & 0x600) == 0x400)
+ outx = 0x3ff, clipped = true;
else
- *outx &= 0x3ff;
+ outx &= 0x3ff;
- /* apply clipping logic to Y */
- if ((*outy & 0x600) == 0x200)
- *outy = 0x000, clipped = true;
- else if ((*outy & 0x600) == 0x400)
- *outy = 0x3ff, clipped = true;
+ // apply clipping logic to Y
+ if ((outy & 0x600) == 0x200)
+ outy = 0x000, clipped = true;
+ else if ((outy & 0x600) == 0x400)
+ outy = 0x3ff, clipped = true;
else
- *outy &= 0x3ff;
+ outy &= 0x3ff;
- /* convert into .16 values */
- *outx = (*outx - (m_min_x - 512)) << 16;
- *outy = (*outy - (m_min_y - 512)) << 16;
+ // convert into .16 values
+ outx = (outx - (m_min_x - 512)) << 16;
+ outy = (outy - (m_min_y - 512)) << 16;
return clipped;
}
void segag80v_state::sega_generate_vector_list()
{
- uint8_t *sintable = memregion("proms")->base();
- double total_time = 1.0 / (double)IRQ_CLOCK;
- uint16_t symaddr = 0;
- uint8_t *vectorram = m_vectorram;
+ attoseconds_t time_remaining = IRQ_ATTOS;
+ u8 *sintable = memregion("proms")->base();
+ u8 *vectorram = m_vectorram;
+ u16 symaddr = 0;
m_vector->clear_list();
- /* Loop until we run out of time. */
- while (total_time > 0)
+ // Loop until we run out of time.
+ while (time_remaining > 0)
{
- uint16_t curx, cury, xaccum, yaccum;
- uint16_t vecaddr, symangle;
- uint8_t scale, draw;
-
- /* The "draw" flag is clocked at the end of phase 0. */
- draw = vectorram[symaddr++ & 0xfff];
+ // The "draw" flag is clocked at the end of phase 0.
+ u8 draw = vectorram[symaddr++ & 0xfff];
- /* The low byte of the X coordinate is latched into the */
- /* up/down counters at U15/U16 during phase 1. */
- curx = vectorram[symaddr++ & 0xfff];
+ // The low byte of the X coordinate is latched into the
+ // up/down counters at U15/U16 during phase 1.
+ u16 curx = vectorram[symaddr++ & 0xfff];
- /* The low 3 bits of the high byte of the X coordinate are */
- /* latched into the up/down counter at U17 during phase 2. */
- /* Bit 2 of the input is latched as both bit 2 and 3. */
+ // The low 3 bits of the high byte of the X coordinate are
+ // latched into the up/down counter at U17 during phase 2.
+ // Bit 2 of the input is latched as both bit 2 and 3.
curx |= (vectorram[symaddr++ & 0xfff] & 7) << 8;
curx |= (curx << 1) & 0x800;
- /* The low byte of the Y coordinate is latched into the */
- /* up/down counters at U18/U19 during phase 3. */
- cury = vectorram[symaddr++ & 0xfff];
+ // The low byte of the Y coordinate is latched into the
+ // up/down counters at U18/U19 during phase 3.
+ u16 cury = vectorram[symaddr++ & 0xfff];
- /* The low 3 bits of the high byte of the X coordinate are */
- /* latched into the up/down counter at U17 during phase 4. */
- /* Bit 2 of the input is latched as both bit 2 and 3. */
+ // The low 3 bits of the high byte of the X coordinate are
+ // latched into the up/down counter at U17 during phase 4.
+ // Bit 2 of the input is latched as both bit 2 and 3.
cury |= (vectorram[symaddr++ & 0xfff] & 7) << 8;
cury |= (cury << 1) & 0x800;
- /* The low byte of the vector address is latched into the */
- /* counters at U10/U11 during phase 5. */
- vecaddr = vectorram[symaddr++ & 0xfff];
+ // The low byte of the vector address is latched into the
+ // counters at U10/U11 during phase 5.
+ u16 vecaddr = vectorram[symaddr++ & 0xfff];
- /* The low 4 bits of the high byte of the vector address is */
- /* latched into the counter at U12 during phase 6. */
+ // The low 4 bits of the high byte of the vector address is
+ // latched into the counter at U12 during phase 6.
vecaddr |= (vectorram[symaddr++ & 0xfff] & 0xf) << 8;
- /* The low byte of the symbol angle is latched into the tri- */
- /* state flip flop at U55 at the end of phase 7. */
- symangle = vectorram[symaddr++ & 0xfff];
+ // The low byte of the symbol angle is latched into the tri-
+ // state flip flop at U55 at the end of phase 7.
+ u16 symangle = vectorram[symaddr++ & 0xfff];
- /* The low 2 bits of the high byte of the symbol angle are */
- /* latched into flip flops at U26 at the end of phase 8. */
+ // The low 2 bits of the high byte of the symbol angle are
+ // latched into flip flops at U26 at the end of phase 8.
symangle |= (vectorram[symaddr++ & 0xfff] & 3) << 8;
- /* The scale is latched in phase 9 as the X input to the */
- /* 25LS14 multiplier at U8. */
- scale = vectorram[symaddr++ & 0xfff];
+ // The scale is latched in phase 9 as the X input to the
+ // 25LS14 multiplier at U8.
+ u8 scale = vectorram[symaddr++ & 0xfff];
- /* Account for the 10 phases so far. */
- total_time -= 10.0 / (double)U51_CLOCK;
+ // Account for the 10 phases so far.
+ time_remaining -= 10 * U51_ATTOS;
- /* Skip the rest if we're not drawing this symbol. */
+ // Skip the rest if we're not drawing this symbol.
if (draw & 1)
{
- int adjx, adjy, clipped;
-
- /* Add a starting point to the vector list. */
- clipped = adjust_xy(curx, cury, &adjx, &adjy);
+ // Add a starting point to the vector list.
+ int adjx, adjy;
+ bool clipped = adjust_xy(curx, cury, adjx, adjy);
if (!clipped)
m_vector->add_point(adjx, adjy, 0, 0);
- /* Loop until we run out of time. */
- while (total_time > 0)
+ // Loop until we run out of time.
+ while (time_remaining > 0)
{
- uint16_t vecangle, length, deltax, deltay;
- uint8_t attrib, intensity;
- uint32_t color;
-
- /* The 'attribute' byte is latched at the end of phase 10 into */
- /* the tri-state flip flop at U2. The low bit controls whether */
- /* or not the beam is enabled. Bits 1-6 control the RGB color */
- /* (2 bits per component). In addition, bit 7 of this value is */
- /* latched into U52, which controls the pre-load value for the */
- /* phase generator. If bit 7 is high, then the phase generator */
- /* will reset back to 0 and draw a new symbol; if bit 7 is low */
- /* the phase generator will reset back to 10 and draw another */
- /* vector. */
- attrib = vectorram[vecaddr++ & 0xfff];
-
- /* The length of the vector is loaded into the shift registers */
- /* at U6/U7 during phase 11. During phase 12, the 25LS14 */
- /* multiplier at U8 is used to multiply the length by the */
- /* scale that was loaded during phase 9. The length is clocked */
- /* bit by bit out of U6/U7 and the result is clocked into the */
- /* other side. After the multiply, the 9 MSBs are loaded into */
- /* the counter chain at U15/16/17 and are used to count how */
- /* long to draw the vector. */
- length = (vectorram[vecaddr++ & 0xfff] * scale) >> 7;
-
- /* The vector angle low byte is latched at the end of phase 12 */
- /* into the tri-state flip flop at U56. */
- vecangle = vectorram[vecaddr++ & 0xfff];
-
- /* The vector angle high byte is preset on the CD bus during */
- /* phases 13 and 14, and is used as inputs to the adder at */
- /* U46. */
+ // The 'attribute' byte is latched at the end of phase 10 into
+ // the tri-state flip flop at U2. The low bit controls whether
+ // or not the beam is enabled. Bits 1-6 control the RGB color
+ // (2 bits per component). In addition, bit 7 of this value is
+ // latched into U52, which controls the pre-load value for the
+ // phase generator. If bit 7 is high, then the phase generator
+ // will reset back to 0 and draw a new symbol; if bit 7 is low
+ // the phase generator will reset back to 10 and draw another
+ // vector.
+ u8 attrib = vectorram[vecaddr++ & 0xfff];
+
+ // The length of the vector is loaded into the shift registers
+ // at U6/U7 during phase 11. During phase 12, the 25LS14
+ // multiplier at U8 is used to multiply the length by the
+ // scale that was loaded during phase 9. The length is clocked
+ // bit by bit out of U6/U7 and the result is clocked into the
+ // other side. After the multiply, the 9 MSBs are loaded into
+ // the counter chain at U15/16/17 and are used to count how
+ // long to draw the vector.
+ u16 length = (vectorram[vecaddr++ & 0xfff] * scale) >> 7;
+
+ // The vector angle low byte is latched at the end of phase 12
+ // into the tri-state flip flop at U56.
+ u16 vecangle = vectorram[vecaddr++ & 0xfff];
+
+ // The vector angle high byte is preset on the CD bus during
+ // phases 13 and 14, and is used as inputs to the adder at
+ // U46.
vecangle |= (vectorram[vecaddr++ & 0xfff] & 3) << 8;
- /* The X increment value is looked up first (phase 13). The */
- /* sum of the latched symbol angle and the vector angle is */
- /* used as input to the PROM at U39. A0 is tied to ground. */
- /* A1-A9 map to bits 0-8 of the summed angles. The output from */
- /* the PROM is latched into U48. */
- deltax = sintable[((vecangle + symangle) & 0x1ff) << 1];
-
- /* The Y increment value is looked up second (phase 14). The */
- /* angle sum is used once again as the input to the PROM, but */
- /* this time an additional 0x100 is effectively added to it */
- /* before it is used; this separates sin from cos. The output */
- /* from the PROM is latched into U49. */
- deltay = sintable[((vecangle + symangle + 0x100) & 0x1ff) << 1];
-
- /* Account for the 4 phases for data fetching. */
- total_time -= 4.0 / (double)U51_CLOCK;
-
- /* Compute color/intensity values from the attributes */
- color = vector_device::color222((attrib >> 1) & 0x3f);
+ // The X increment value is looked up first (phase 13). The
+ // sum of the latched symbol angle and the vector angle is
+ // used as input to the PROM at U39. A0 is tied to ground.
+ // A1-A9 map to bits 0-8 of the summed angles. The output from
+ // the PROM is latched into U48.
+ u16 deltax = sintable[((vecangle + symangle) & 0x1ff) << 1];
+
+ // The Y increment value is looked up second (phase 14). The
+ // angle sum is used once again as the input to the PROM, but
+ // this time an additional 0x100 is effectively added to it
+ // before it is used; this separates sin from cos. The output
+ // from the PROM is latched into U49.
+ u16 deltay = sintable[((vecangle + symangle + 0x100) & 0x1ff) << 1];
+
+ // Account for the 4 phases for data fetching.
+ time_remaining -= 4 * U51_ATTOS;
+
+ // Compute color/intensity values from the attributes
+ u32 color = vector_device::color222((attrib >> 1) & 0x3f);
+ u8 intensity = 0;
if ((attrib & 1) && color)
intensity = 0xff;
- else
- intensity = 0;
- /* Loop over the length of the vector. */
- clipped = adjust_xy(curx, cury, &adjx, &adjy);
- xaccum = yaccum = 0;
- while (length-- != 0 && total_time > 0)
+ // Loop over the length of the vector.
+ clipped = adjust_xy(curx, cury, adjx, adjy);
+ u16 xaccum = 0;
+ u16 yaccum = 0;
+ while (length-- != 0 && time_remaining > 0)
{
- int newclip;
-
- /* The adders at U44/U45 are used as X accumulators. The value */
- /* from U48 is repeatedly added to itself here. The carry out */
- /* of bit 8 clocks the up/down counters at U15/U16/U17. Bit 7 */
- /* of the input value from U48 is used as a carry in to round */
- /* small values downward and larger values upward. */
+ // The adders at U44/U45 are used as X accumulators. The value
+ // from U48 is repeatedly added to itself here. The carry out
+ // of bit 8 clocks the up/down counters at U15/U16/U17. Bit 7
+ // of the input value from U48 is used as a carry in to round
+ // small values downward and larger values upward.
xaccum += deltax + (deltax >> 7);
- /* Bit 9 of the summed angles controls the direction the up/ */
- /* down counters at U15/U16/U17. */
+ // Bit 9 of the summed angles controls the direction the up/
+ // down counters at U15/U16/U17.
if (((vecangle + symangle) & 0x200) == 0)
curx += xaccum >> 8;
else
curx -= xaccum >> 8;
xaccum &= 0xff;
- /* The adders at U46/U47 are used as Y accumulators. The value */
- /* from U49 is repeatedly added to itself here. The carry out */
- /* of bit 8 clocks the up/down counters at U18/U19/U20. Bit 7 */
- /* of the input value from U49 is used as a carry in to round */
- /* small values downward and larger values upward. */
+ // The adders at U46/U47 are used as Y accumulators. The value
+ // from U49 is repeatedly added to itself here. The carry out
+ // of bit 8 clocks the up/down counters at U18/U19/U20. Bit 7
+ // of the input value from U49 is used as a carry in to round
+ // small values downward and larger values upward.
yaccum += deltay + (deltay >> 7);
- /* Bit 9 of the summed angles controls the direction the up/ */
- /* down counters at U18/U19/U20. */
+ // Bit 9 of the summed angles controls the direction the up/
+ // down counters at U18/U19/U20.
if (((vecangle + symangle + 0x100) & 0x200) == 0)
cury += yaccum >> 8;
else
cury -= yaccum >> 8;
yaccum &= 0xff;
- /* Apply the clipping from the DAC circuit. If the values clip */
- /* the beam is turned off, but the computations continue right */
- /* on going. */
- newclip = adjust_xy(curx, cury, &adjx, &adjy);
+ // Apply the clipping from the DAC circuit. If the values clip
+ // the beam is turned off, but the computations continue right
+ // on going.
+ bool newclip = adjust_xy(curx, cury, adjx, adjy);
if (newclip != clipped)
{
- /* if we're just becoming unclipped, add an empty point */
+ // if we're just becoming unclipped, add an empty point
if (!newclip)
m_vector->add_point(adjx, adjy, 0, 0);
- /* otherwise, add a colored point */
+ // otherwise, add a colored point
else
m_vector->add_point(adjx, adjy, color, intensity);
}
clipped = newclip;
- /* account for vector drawing time */
- total_time -= 1.0 / (double)VCL_CLOCK;
+ // account for vector drawing time
+ time_remaining -= VCL_ATTOS;
}
- /* We're done; if we are not clipped, add a final point. */
+ // We're done; if we are not clipped, add a final point.
if (!clipped)
m_vector->add_point(adjx, adjy, color, intensity);
- /* if the high bit of the attribute is set, we break out of */
- /* this loop and fetch another symbol */
+ // if the high bit of the attribute is set, we break out of
+ // this loop and fetch another symbol
if (attrib & 0x80)
break;
}
}
- /* if the high bit of the draw flag is set, we break out of this loop */
- /* and stop the rendering altogether for this frame. */
+ // if the high bit of the draw flag is set, we break out of this loop
+ // and stop the rendering altogether for this frame.
if (draw & 0x80)
break;
}
+
+ // set the drawing end time for this frame
+ m_draw_end_time = machine().scheduler().time() + attotime(0, IRQ_ATTOS - time_remaining);
}
@@ -328,12 +324,12 @@ void segag80v_state::video_start()
if (!m_vectorram.bytes())
throw emu_fatalerror("segag80v_state::video_start: !vectorram.bytes()");
- m_min_x =m_screen->visible_area().min_x;
- m_min_y =m_screen->visible_area().min_y;
+ m_min_x = m_screen->visible_area().min_x;
+ m_min_y = m_screen->visible_area().min_y;
}
-uint32_t segag80v_state::screen_update_segag80v(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+u32 segag80v_state::screen_update_segag80v(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
sega_generate_vector_list();
m_vector->screen_update(screen, bitmap, cliprect);