summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/pokey.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound/pokey.cpp')
-rw-r--r--src/devices/sound/pokey.cpp580
1 files changed, 314 insertions, 266 deletions
diff --git a/src/devices/sound/pokey.cpp b/src/devices/sound/pokey.cpp
index f749afad2ae..35f389fcd58 100644
--- a/src/devices/sound/pokey.cpp
+++ b/src/devices/sound/pokey.cpp
@@ -2,15 +2,34 @@
// copyright-holders:Brad Oliver, Eric Smith, Juergen Buchmueller
/*****************************************************************************
*
- * POKEY chip emulator 4.6
+ * POKEY chip emulator 4.9
*
* Based on original info found in Ron Fries' Pokey emulator,
* with additions by Brad Oliver, Eric Smith and Juergen Buchmueller,
* paddle (a/d conversion) details from the Atari 400/800 Hardware Manual.
* Polynomial algorithms according to info supplied by Perry McFarlane.
+ * Additional improvements from Mike Saarna's A7800 MAME fork.
+ *
+ * 4.9:
+ * - Two-tone mode updated for better accuracy.
+ *
+ * 4.8:
+ * - Poly5 related modes had a pitch shift issue. The poly4/5 init routine
+ * was replaced with one based on Altira's implementation, which resolved
+ * the issue.
+ *
+ * 4.7:
+ * [1] https://www.virtualdub.org/downloads/Altirra%20Hardware%20Reference%20Manual.pdf
+ * - updated to reflect that borrowing cycle delays only impacts voices
+ * running at 1.79MHz. (+4 cycles unlinked, or +7 cycles linked)
+ * At slower speeds, cycle overhead still occurs, but only affects
+ * the phase of the timer period, not the actual length.
+ * - Initial two-tone support added. Emulation of two-tone is limited to
+ * audio output effects, and doesn't incorporate any of the aspects of
+ * SIO serial transfer.
*
* 4.6:
- * [1] http://ploguechipsounds.blogspot.de/2009/10/how-i-recorded-and-decoded-pokeys.html
+ * [2] http://ploguechipsounds.blogspot.de/2009/10/how-i-recorded-and-decoded-pokeys.html
* - changed audio emulation to emulate borrow 3 clock delay and
* proper channel reset. New frequency only becomes effective
* after the counter hits 0. Emulation also treats counters
@@ -19,6 +38,7 @@
*
* 4.51:
* - changed to use the attotime datatype
+ *
* 4.5:
* - changed the 9/17 bit polynomial formulas such that the values
* required for the Tempest Pokey protection will be found.
@@ -29,22 +49,27 @@
* - reading the RNG returns the shift register contents ^ 0xff.
* That way resetting the Pokey with SKCTL (which resets the
* polynomial shifters to 0) returns the expected 0xff value.
+ *
* 4.4:
* - reversed sample values to make OFF channels produce a zero signal.
* actually de-reversed them; don't remember that I reversed them ;-/
+ *
* 4.3:
* - for POT inputs returning zero, immediately assert the ALLPOT
* bit after POTGO is written, otherwise start trigger timer
* depending on SK_PADDLE mode, either 1-228 scanlines or 1-2
* scanlines, depending on the SK_PADDLE bit of SKCTL.
+ *
* 4.2:
* - half volume for channels which are inaudible (this should be
* close to the real thing).
+ *
* 4.1:
* - default gain increased to closely match the old code.
* - random numbers repeat rate depends on POLY9 flag too!
* - verified sound output with many, many Atari 800 games,
* including the SUPPRESS_INAUDIBLE optimizations.
+ *
* 4.0:
* - rewritten from scratch.
* - 16bit stream interface.
@@ -75,21 +100,24 @@
#define POKEY_DEFAULT_GAIN (32767/11/4)
-#define VERBOSE 0
-#define VERBOSE_SOUND 0
-#define VERBOSE_TIMER 0
-#define VERBOSE_POLY 0
-#define VERBOSE_RAND 0
+#define VERBOSE_SOUND (1U << 1)
+#define VERBOSE_TIMER (1U << 2)
+#define VERBOSE_POLY (1U << 3)
+#define VERBOSE_RAND (1U << 4)
+#define VERBOSE_IRQ (1U << 5)
+#define VERBOSE (0)
-#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+#include "logmacro.h"
-#define LOG_SOUND(x) do { if (VERBOSE_SOUND) logerror x; } while (0)
+#define LOG_SOUND(...) LOGMASKED(VERBOSE_SOUND, __VA_ARGS__)
-#define LOG_TIMER(x) do { if (VERBOSE_TIMER) logerror x; } while (0)
+#define LOG_TIMER(...) LOGMASKED(VERBOSE_TIMER, __VA_ARGS__)
-#define LOG_POLY(x) do { if (VERBOSE_POLY) logerror x; } while (0)
+#define LOG_POLY(...) LOGMASKED(VERBOSE_POLY, __VA_ARGS__)
-#define LOG_RAND(x) do { if (VERBOSE_RAND) logerror x; } while (0)
+#define LOG_RAND(...) LOGMASKED(VERBOSE_RAND, __VA_ARGS__)
+
+#define LOG_IRQ(...) LOGMASKED(VERBOSE_IRQ, __VA_ARGS__)
#define CHAN1 0
#define CHAN2 1
@@ -139,7 +167,7 @@
/* SKCTL (W/D20F) */
#define SK_BREAK 0x80 /* serial out break signal */
#define SK_BPS 0x70 /* bits per second */
-#define SK_FM 0x08 /* FM mode */
+#define SK_TWOTONE 0x08 /* Two tone mode */
#define SK_PADDLE 0x04 /* fast paddle a/d conversion */
#define SK_RESET 0x03 /* reset serial/keyboard interface */
#define SK_KEYSCAN 0x02 /* key scanning enabled ? */
@@ -152,9 +180,6 @@
#define CLK_28 1
#define CLK_114 2
-constexpr unsigned pokey_device::FREQ_17_EXACT;
-
-
// device type definition
DEFINE_DEVICE_TYPE(POKEY, pokey_device, "pokey", "Atari C012294 POKEY")
@@ -167,20 +192,23 @@ DEFINE_DEVICE_TYPE(POKEY, pokey_device, "pokey", "Atari C012294 POKEY")
// pokey_device - constructor
//-------------------------------------------------
-pokey_device::pokey_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, POKEY, tag, owner, clock),
- device_sound_interface(mconfig, *this),
- device_execute_interface(mconfig, *this),
- device_state_interface(mconfig, *this),
- m_icount(0),
- m_stream(nullptr),
- m_pot_r_cb(*this),
- m_allpot_r_cb(*this),
- m_serin_r_cb(*this),
- m_serout_w_cb(*this),
- m_keyboard_r(*this),
- m_irq_f(*this),
- m_output_type(LEGACY_LINEAR)
+pokey_device::pokey_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, POKEY, tag, owner, clock),
+ device_sound_interface(mconfig, *this),
+ device_execute_interface(mconfig, *this),
+ device_state_interface(mconfig, *this),
+ m_icount(0),
+ m_stream(nullptr),
+ m_pot_r_cb(*this, 0),
+ m_allpot_r_cb(*this, 0),
+ m_serin_r_cb(*this, 0),
+ m_serout_w_cb(*this),
+ m_irq_w_cb(*this),
+ m_keyboard_r(*this),
+ m_output_type(LEGACY_LINEAR),
+ m_serout_ready_timer(nullptr),
+ m_serout_complete_timer(nullptr),
+ m_serin_ready_timer(nullptr)
{
}
@@ -192,19 +220,15 @@ void pokey_device::device_start()
{
//int sample_rate = clock();
- /* Setup channels */
- for (int i=0; i<POKEY_CHANNELS; i++)
- {
- m_channel[i].m_parent = this;
- m_channel[i].m_INTMask = 0;
- }
+ // Set up channels
+ for (pokey_channel &chan : m_channel)
+ chan.m_INTMask = 0;
m_channel[CHAN1].m_INTMask = IRQ_TIMR1;
m_channel[CHAN2].m_INTMask = IRQ_TIMR2;
m_channel[CHAN4].m_INTMask = IRQ_TIMR4;
- // bind callbacks
+ // bind delegates
m_keyboard_r.resolve();
- m_irq_f.resolve();
/* calculate the A/D times
* In normal, slow mode (SKCTL bit SK_PADDLE is clear) the conversion
@@ -215,20 +239,29 @@ void pokey_device::device_start()
*/
/* initialize the poly counters */
- poly_init_4_5(m_poly4, 4, 1, 0);
- poly_init_4_5(m_poly5, 5, 2, 1);
+ poly_init_4_5(m_poly4, 4);
+ poly_init_4_5(m_poly5, 5);
/* initialize 9 / 17 arrays */
poly_init_9_17(m_poly9, 9);
poly_init_9_17(m_poly17, 17);
vol_init();
+ for (int i=0; i<4; i++)
+ m_channel[i].m_AUDC = 0xb0;
+
/* The pokey does not have a reset line. These should be initialized
* with random values.
*/
- m_KBCODE = 0x09; /* Atari 800 'no key' */
- m_SKCTL = SK_RESET; /* let the RNG run after reset */
+ m_KBCODE = 0x09; // Atari 800 'no key'
+ m_SKCTL = 0;
+
+ // TODO: several a7800 demos don't explicitly reset pokey at startup
+ // See https://atariage.com/forums/topic/337317-a7800-52-release/ and
+ // https://atariage.com/forums/topic/268458-a7800-the-atari-7800-emulator/?do=findComment&comment=5079170)
+ // m_SKCTL = SK_RESET;
+
m_SKSTAT = 0;
/* This bit should probably get set later. Acid5200 pokey_setoc test tests this. */
m_IRQST = IRQ_SEROC;
@@ -251,17 +284,11 @@ void pokey_device::device_start()
std::fill(std::begin(m_clock_cnt), std::end(m_clock_cnt), 0);
std::fill(std::begin(m_POTx), std::end(m_POTx), 0);
- m_pot_r_cb.resolve_all();
- m_allpot_r_cb.resolve();
- m_serin_r_cb.resolve();
- m_serout_w_cb.resolve_safe();
-
m_stream = stream_alloc(0, 1, clock());
- timer_alloc(SYNC_WRITE); /* timer for sync operation */
- timer_alloc(SYNC_NOOP);
- timer_alloc(SYNC_POT);
- timer_alloc(SYNC_SET_IRQST);
+ m_serout_ready_timer = timer_alloc(FUNC(pokey_device::serout_ready_irq), this);
+ m_serout_complete_timer = timer_alloc(FUNC(pokey_device::serout_complete_irq), this);
+ m_serin_ready_timer = timer_alloc(FUNC(pokey_device::serin_ready_irq), this);
save_item(STRUCT_MEMBER(m_channel, m_borrow_cnt));
save_item(STRUCT_MEMBER(m_channel, m_counter));
@@ -323,6 +350,10 @@ void pokey_device::device_start()
void pokey_device::device_reset()
{
m_stream->update();
+ // a1200xl reads POT4 twice at startup for reading self-test mode jumpers.
+ // we need to update POT counters here otherwise it will boot to self-test
+ // the first time around no matter the setting.
+ pokey_potgo();
}
@@ -354,60 +385,59 @@ void pokey_device::device_clock_changed()
}
//-------------------------------------------------
-// stream_generate - handle update requests for
-// our sound stream
+// timer callbacks
//-------------------------------------------------
-void pokey_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(pokey_device::serout_ready_irq)
{
- switch (id)
+ if (m_IRQEN & IRQ_SEROR)
{
- case 3:
- /* serout_ready_cb */
- if (m_IRQEN & IRQ_SEROR)
- {
- m_IRQST |= IRQ_SEROR;
- if (!m_irq_f.isnull())
- m_irq_f(IRQ_SEROR);
- }
- break;
- case 4:
- /* serout_complete */
- if (m_IRQEN & IRQ_SEROC)
- {
- m_IRQST |= IRQ_SEROC;
- if (!m_irq_f.isnull())
- m_irq_f(IRQ_SEROC);
- }
- break;
- case 5:
- /* serin_ready */
- if (m_IRQEN & IRQ_SERIN)
- {
- m_IRQST |= IRQ_SERIN;
- if (!m_irq_f.isnull())
- m_irq_f(IRQ_SERIN);
- }
- break;
- case SYNC_WRITE:
- {
- offs_t offset = (param >> 8) & 0xff;
- uint8_t data = param & 0xff;
- write_internal(offset, data);
- }
- break;
- case SYNC_NOOP:
- /* do nothing, caused by a forced resync */
- break;
- case SYNC_POT:
- //logerror("x %02x \n", (param & 0x20));
- m_ALLPOT |= (param & 0xff);
- break;
- case SYNC_SET_IRQST:
+ m_IRQST |= IRQ_SEROR;
+ LOG_IRQ("POKEY SEROR IRQ raised\n");
+ m_irq_w_cb(ASSERT_LINE);
+ }
+}
+
+TIMER_CALLBACK_MEMBER(pokey_device::serout_complete_irq)
+{
+ m_IRQST |= IRQ_SEROC;
+ if (m_IRQEN & IRQ_SEROC)
+ {
+ LOG_IRQ("POKEY SEROC IRQ raised\n");
+ m_irq_w_cb(ASSERT_LINE);
+ }
+}
+
+TIMER_CALLBACK_MEMBER(pokey_device::serin_ready_irq)
+{
+ if (m_IRQEN & IRQ_SERIN)
+ {
+ m_IRQST |= IRQ_SERIN;
+ LOG_IRQ("POKEY SERIN IRQ raised\n");
+ m_irq_w_cb(ASSERT_LINE);
+ }
+}
+
+TIMER_CALLBACK_MEMBER(pokey_device::sync_write)
+{
+ offs_t offset = (param >> 8) & 0xff;
+ uint8_t data = param & 0xff;
+ write_internal(offset, data);
+}
+
+TIMER_CALLBACK_MEMBER(pokey_device::sync_pot)
+{
+ //logerror("x %02x \n", (param & 0x20));
+ m_ALLPOT |= (param & 0xff);
+}
+
+TIMER_CALLBACK_MEMBER(pokey_device::sync_set_irqst)
+{
+ if (m_IRQEN & param)
+ {
+ LOG_IRQ("POKEY TIMR%d IRQ raised\n", param);
m_IRQST |= (param & 0xff);
- break;
- default:
- throw emu_fatalerror("Unknown id in pokey_device::device_timer");
+ m_irq_w_cb(ASSERT_LINE);
}
}
@@ -443,9 +473,9 @@ void pokey_device::step_keyboard()
/* check if the break IRQ is enabled */
if (m_IRQEN & IRQ_BREAK)
{
+ LOG_IRQ("POKEY BREAK IRQ raised\n");
m_IRQST |= IRQ_BREAK;
- if (!m_irq_f.isnull())
- m_irq_f(IRQ_BREAK);
+ m_irq_w_cb(ASSERT_LINE);
}
}
break;
@@ -471,20 +501,20 @@ void pokey_device::step_keyboard()
}
break;
case 1: /* waiting for key confirmation */
- if ((m_kbd_latch & 0x3f) == m_kbd_cnt)
+ if (!(m_SKCTL & SK_DEBOUNCE) || (m_kbd_latch & 0x3f) == m_kbd_cnt)
{
if (ret & 1)
{
- m_KBCODE = m_kbd_latch;
+ m_KBCODE = (m_SKCTL & SK_DEBOUNCE) ? m_kbd_latch : (m_kbd_latch & 0xc0) | m_kbd_cnt;
m_SKSTAT |= SK_KEYBD;
if (m_IRQEN & IRQ_KEYBD)
{
/* last interrupt not acknowledged ? */
if (m_IRQST & IRQ_KEYBD)
m_SKSTAT |= SK_KBERR;
+ LOG_IRQ("POKEY KEYBD IRQ raised\n");
m_IRQST |= IRQ_KEYBD;
- if (!m_irq_f.isnull())
- m_irq_f(IRQ_KEYBD);
+ m_irq_w_cb(ASSERT_LINE);
}
m_kbd_state++;
}
@@ -493,16 +523,14 @@ void pokey_device::step_keyboard()
}
break;
case 2: /* waiting for release */
- if ((m_kbd_latch & 0x3f) == m_kbd_cnt)
+ if (!(m_SKCTL & SK_DEBOUNCE) || (m_kbd_latch & 0x3f) == m_kbd_cnt)
{
if ((ret & 1)==0)
m_kbd_state++;
- else
- m_SKSTAT |= SK_KEYBD;
}
break;
case 3:
- if ((m_kbd_latch & 0x3f) == m_kbd_cnt)
+ if (!(m_SKCTL & SK_DEBOUNCE) || (m_kbd_latch & 0x3f) == m_kbd_cnt)
{
if (ret & 1)
m_kbd_state = 2;
@@ -531,7 +559,7 @@ void pokey_device::step_pot()
}
// some pots latched?
if (upd != 0)
- synchronize(SYNC_POT, upd);
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(pokey_device::sync_pot), this), upd);
}
/*
@@ -542,11 +570,12 @@ void pokey_device::step_pot()
*
*/
-void pokey_device::step_one_clock(void)
+void pokey_device::step_one_clock()
{
- /* Clocks only count if we are not in a reset */
if (m_SKCTL & SK_RESET)
{
+ /* Clocks only count if we are not in a reset */
+
/* polynom pointers */
if (++m_p4 == 0x0000f)
m_p4 = 0;
@@ -572,21 +601,36 @@ void pokey_device::step_one_clock(void)
clock_triggered[CLK_114] = 1;
}
- int const base_clock = (m_AUDCTL & CLK_15KHZ) ? CLK_114 : CLK_28;
- int clk = (m_AUDCTL & CH1_HICLK) ? CLK_1 : base_clock;
- if (clock_triggered[clk])
- m_channel[CHAN1].inc_chan();
+ if ((m_AUDCTL & CH1_HICLK) && (clock_triggered[CLK_1]))
+ {
+ if (m_AUDCTL & CH12_JOINED)
+ m_channel[CHAN1].inc_chan(*this, 7);
+ else
+ m_channel[CHAN1].inc_chan(*this, 4);
+ }
+
+ int base_clock = (m_AUDCTL & CLK_15KHZ) ? CLK_114 : CLK_28;
+
+ if ((!(m_AUDCTL & CH1_HICLK)) && (clock_triggered[base_clock]))
+ m_channel[CHAN1].inc_chan(*this, 1);
+
+ if ((m_AUDCTL & CH3_HICLK) && (clock_triggered[CLK_1]))
+ {
+ if (m_AUDCTL & CH34_JOINED)
+ m_channel[CHAN3].inc_chan(*this, 7);
+ else
+ m_channel[CHAN3].inc_chan(*this, 4);
+ }
- clk = (m_AUDCTL & CH3_HICLK) ? CLK_1 : base_clock;
- if (clock_triggered[clk])
- m_channel[CHAN3].inc_chan();
+ if ((!(m_AUDCTL & CH3_HICLK)) && (clock_triggered[base_clock]))
+ m_channel[CHAN3].inc_chan(*this, 1);
if (clock_triggered[base_clock])
{
if (!(m_AUDCTL & CH12_JOINED))
- m_channel[CHAN2].inc_chan();
+ m_channel[CHAN2].inc_chan(*this, 1);
if (!(m_AUDCTL & CH34_JOINED))
- m_channel[CHAN4].inc_chan();
+ m_channel[CHAN4].inc_chan(*this, 1);
}
/* Potentiometer handling */
@@ -598,38 +642,26 @@ void pokey_device::step_one_clock(void)
step_keyboard();
}
- /* do CHAN2 before CHAN1 because CHAN1 may set borrow! */
- if (m_channel[CHAN2].check_borrow())
+ if (m_channel[CHAN3].check_borrow())
{
- bool const isJoined(m_AUDCTL & CH12_JOINED);
- if (isJoined)
- m_channel[CHAN1].reset_channel();
- m_channel[CHAN2].reset_channel();
- process_channel(CHAN2);
-
- /* check if some of the requested timer interrupts are enabled */
- if ((m_IRQST & IRQ_TIMR2) && !m_irq_f.isnull())
- m_irq_f(IRQ_TIMR2);
- }
+ if (m_AUDCTL & CH34_JOINED)
+ m_channel[CHAN4].inc_chan(*this, 1);
+ else
+ m_channel[CHAN3].reset_channel();
- if (m_channel[CHAN1].check_borrow())
- {
- bool const isJoined(m_AUDCTL & CH12_JOINED);
- if (isJoined)
- m_channel[CHAN2].inc_chan();
+ process_channel(CHAN3);
+ /* is this a filtering channel (3/4) and is the filter active? */
+ if (m_AUDCTL & CH1_FILTER)
+ m_channel[CHAN1].sample();
else
- m_channel[CHAN1].reset_channel();
- process_channel(CHAN1);
- /* check if some of the requested timer interrupts are enabled */
- if ((m_IRQST & IRQ_TIMR1) && !m_irq_f.isnull())
- m_irq_f(IRQ_TIMR1);
+ m_channel[CHAN1].m_filter_sample = 1;
+
+ m_old_raw_inval = true;
}
- /* do CHAN4 before CHAN3 because CHAN3 may set borrow! */
if (m_channel[CHAN4].check_borrow())
{
- bool const isJoined(m_AUDCTL & CH34_JOINED);
- if (isJoined)
+ if (m_AUDCTL & CH34_JOINED)
m_channel[CHAN3].reset_channel();
m_channel[CHAN4].reset_channel();
process_channel(CHAN4);
@@ -638,23 +670,36 @@ void pokey_device::step_one_clock(void)
m_channel[CHAN2].sample();
else
m_channel[CHAN2].m_filter_sample = 1;
- if ((m_IRQST & IRQ_TIMR4) && !m_irq_f.isnull())
- m_irq_f(IRQ_TIMR4);
+
+ m_old_raw_inval = true;
}
- if (m_channel[CHAN3].check_borrow())
+ if ((m_SKCTL & SK_TWOTONE) && (m_channel[CHAN2].m_borrow_cnt == 1))
{
- bool const isJoined(m_AUDCTL & CH34_JOINED);
- if (isJoined)
- m_channel[CHAN4].inc_chan();
- else
- m_channel[CHAN3].reset_channel();
- process_channel(CHAN3);
- /* is this a filtering channel (3/4) and is the filter active? */
- if (m_AUDCTL & CH1_FILTER)
- m_channel[CHAN1].sample();
+ m_channel[CHAN1].reset_channel();
+ m_old_raw_inval = true;
+ }
+
+ if (m_channel[CHAN1].check_borrow())
+ {
+ if (m_AUDCTL & CH12_JOINED)
+ m_channel[CHAN2].inc_chan(*this, 1);
else
- m_channel[CHAN1].m_filter_sample = 1;
+ m_channel[CHAN1].reset_channel();
+
+ // TODO: If two-tone is enabled *and* serial output == 1 then reset the channel 2 timer.
+
+ process_channel(CHAN1);
+ }
+
+ if (m_channel[CHAN2].check_borrow())
+ {
+ if (m_AUDCTL & CH12_JOINED)
+ m_channel[CHAN1].reset_channel();
+
+ m_channel[CHAN2].reset_channel();
+
+ process_channel(CHAN2);
}
if (m_old_raw_inval)
@@ -667,10 +712,8 @@ void pokey_device::step_one_clock(void)
}
if (m_out_raw != sum)
- {
- //printf("forced update %08d %08x\n", m_icount, m_out_raw);
m_stream->update();
- }
+
m_old_raw_inval = false;
m_out_raw = sum;
}
@@ -755,7 +798,7 @@ uint8_t pokey_device::read(offs_t offset)
{
int data, pot;
- synchronize(SYNC_NOOP); /* force resync */
+ machine().scheduler().synchronize(); /* force resync */
switch (offset & 15)
{
@@ -766,12 +809,12 @@ uint8_t pokey_device::read(offs_t offset)
{
/* we have a value measured */
data = m_POTx[pot];
- LOG(("POKEY '%s' read POT%d (final value) $%02x\n", tag(), pot, data));
+ LOG("%s: POKEY read POT%d (final value) $%02x\n", machine().describe_context(), pot, data);
}
else
{
data = m_pot_counter;
- LOG(("POKEY '%s' read POT%d (interpolated) $%02x\n", tag(), pot, data));
+ LOG("%s: POKEY read POT%d (interpolated) $%02x\n", machine().describe_context(), pot, data);
}
break;
@@ -783,17 +826,17 @@ uint8_t pokey_device::read(offs_t offset)
if ((m_SKCTL & SK_RESET) == 0)
{
data = m_ALLPOT;
- LOG(("POKEY '%s' ALLPOT internal $%02x (reset)\n", tag(), data));
+ LOG("%s: POKEY ALLPOT internal $%02x (reset)\n", machine().describe_context(), data);
}
- else if (!m_allpot_r_cb.isnull())
+ else if (!m_allpot_r_cb.isunset())
{
m_ALLPOT = data = m_allpot_r_cb(offset);
- LOG(("%s: POKEY '%s' ALLPOT callback $%02x\n", machine().describe_context(), tag(), data));
+ LOG("%s: POKEY ALLPOT callback $%02x\n", machine().describe_context(), data);
}
else
{
data = m_ALLPOT ^ 0xff;
- LOG(("POKEY '%s' ALLPOT internal $%02x\n", tag(), data));
+ LOG("%s: POKEY ALLPOT internal $%02x\n", machine().describe_context(), data);
}
break;
@@ -805,37 +848,37 @@ uint8_t pokey_device::read(offs_t offset)
if (m_AUDCTL & POLY9)
{
data = m_poly9[m_p9] & 0xff;
- LOG_RAND(("POKEY '%s' rand9[$%05x]: $%02x\n", tag(), m_p9, data));
+ LOG_RAND("%s: POKEY rand9[$%05x]: $%02x\n", machine().describe_context(), m_p9, data);
}
else
{
data = (m_poly17[m_p17] >> 8) & 0xff;
- LOG_RAND(("POKEY '%s' rand17[$%05x]: $%02x\n", tag(), m_p17, data));
+ LOG_RAND("%s: POKEY rand17[$%05x]: $%02x\n", machine().describe_context(), m_p17, data);
}
break;
case SERIN_C:
- if (!m_serin_r_cb.isnull())
+ if (!m_serin_r_cb.isunset())
m_SERIN = m_serin_r_cb(offset);
data = m_SERIN;
- LOG(("POKEY '%s' SERIN $%02x\n", tag(), data));
+ LOG("%s: POKEY SERIN $%02x\n", machine().describe_context(), data);
break;
case IRQST_C:
/* IRQST is an active low input port; we keep it active high */
/* internally to ease the (un-)masking of bits */
data = m_IRQST ^ 0xff;
- LOG(("POKEY '%s' IRQST $%02x\n", tag(), data));
+ LOG("%s: POKEY IRQST $%02x\n", machine().describe_context(), data);
break;
case SKSTAT_C:
/* SKSTAT is also an active low input port */
data = m_SKSTAT ^ 0xff;
- LOG(("POKEY '%s' SKSTAT $%02x\n", tag(), data));
+ LOG("%s: POKEY SKSTAT $%02x\n", machine().describe_context(), data);
break;
default:
- LOG(("POKEY '%s' register $%02x\n", tag(), offset));
+ LOG("%s: POKEY register $%02x\n", machine().describe_context(), offset);
data = 0xff;
break;
}
@@ -849,7 +892,7 @@ uint8_t pokey_device::read(offs_t offset)
void pokey_device::write(offs_t offset, uint8_t data)
{
- synchronize(SYNC_WRITE, (offset << 8) | data);
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(pokey_device::sync_write), this), (offset << 8) | data);
}
void pokey_device::write_internal(offs_t offset, uint8_t data)
@@ -858,59 +901,59 @@ void pokey_device::write_internal(offs_t offset, uint8_t data)
switch (offset & 15)
{
case AUDF1_C:
- LOG_SOUND(("POKEY '%s' AUDF1 $%02x\n", tag(), data));
+ LOG_SOUND("%s: AUDF1 = $%02x\n", machine().describe_context(), data);
m_channel[CHAN1].m_AUDF = data;
break;
case AUDC1_C:
- LOG_SOUND(("POKEY '%s' AUDC1 $%02x (%s)\n", tag(), data, audc2str(data)));
+ LOG_SOUND("%s: POKEY AUDC1 $%02x (%s)\n", machine().describe_context(), data, audc2str(data));
m_channel[CHAN1].m_AUDC = data;
m_old_raw_inval = true;
break;
case AUDF2_C:
- LOG_SOUND(("POKEY '%s' AUDF2 $%02x\n", tag(), data));
+ LOG_SOUND("%s: POKEY AUDF2 $%02x\n", machine().describe_context(), data);
m_channel[CHAN2].m_AUDF = data;
break;
case AUDC2_C:
- LOG_SOUND(("POKEY '%s' AUDC2 $%02x (%s)\n", tag(), data, audc2str(data)));
+ LOG_SOUND("%s: POKEY AUDC2 $%02x (%s)\n", machine().describe_context(), data, audc2str(data));
m_channel[CHAN2].m_AUDC = data;
m_old_raw_inval = true;
break;
case AUDF3_C:
- LOG_SOUND(("POKEY '%s' AUDF3 $%02x\n", tag(), data));
+ LOG_SOUND("%s: POKEY AUDF3 $%02x\n", machine().describe_context(), data);
m_channel[CHAN3].m_AUDF = data;
break;
case AUDC3_C:
- LOG_SOUND(("POKEY '%s' AUDC3 $%02x (%s)\n", tag(), data, audc2str(data)));
+ LOG_SOUND("%s: POKEY AUDC3 $%02x (%s)\n", machine().describe_context(), data, audc2str(data));
m_channel[CHAN3].m_AUDC = data;
m_old_raw_inval = true;
break;
case AUDF4_C:
- LOG_SOUND(("POKEY '%s' AUDF4 $%02x\n", tag(), data));
+ LOG_SOUND("%s: POKEY AUDF4 $%02x\n", machine().describe_context(), data);
m_channel[CHAN4].m_AUDF = data;
break;
case AUDC4_C:
- LOG_SOUND(("POKEY '%s' AUDC4 $%02x (%s)\n", tag(), data, audc2str(data)));
+ LOG_SOUND("%s: POKEY AUDC4 $%02x (%s)\n", machine().describe_context(), data, audc2str(data));
m_channel[CHAN4].m_AUDC = data;
m_old_raw_inval = true;
break;
case AUDCTL_C:
- if( data == m_AUDCTL )
+ if (data == m_AUDCTL)
return;
- LOG_SOUND(("POKEY '%s' AUDCTL $%02x (%s)\n", tag(), data, audctl2str(data)));
+ LOG_SOUND("%s: POKEY AUDCTL $%02x (%s)\n", machine().describe_context(), data, audctl2str(data));
m_AUDCTL = data;
-
+ m_old_raw_inval = true;
break;
case STIMER_C:
- LOG_TIMER(("POKEY '%s' STIMER $%02x\n", tag(), data));
+ LOG_TIMER("%s: POKEY STIMER $%02x\n", machine().describe_context(), data);
/* From the pokey documentation:
* reset all counters to zero (side effect)
@@ -928,17 +971,23 @@ void pokey_device::write_internal(offs_t offset, uint8_t data)
case SKREST_C:
/* reset SKSTAT */
- LOG(("POKEY '%s' SKREST $%02x\n", tag(), data));
+ LOG("%s: POKEY SKREST $%02x\n", machine().describe_context(), data);
m_SKSTAT &= ~(SK_FRAME|SK_OVERRUN|SK_KBERR);
break;
case POTGO_C:
- LOG(("POKEY '%s' POTGO $%02x\n", tag(), data));
- pokey_potgo();
+ LOG("%s: POKEY POTGO $%02x\n", machine().describe_context(), data);
+ if (m_SKCTL & SK_RESET)
+ pokey_potgo();
break;
case SEROUT_C:
- LOG(("POKEY '%s' SEROUT $%02x\n", tag(), data));
+ LOG("%s: POKEY SEROUT $%02x\n", machine().describe_context(), data);
+ // TODO: convert to real serial comms, fix timings
+ // SEROC (1) serial out in progress (0) serial out complete
+ // in progress status is necessary for a800 telelnk2 to boot
+ m_IRQST &= ~IRQ_SEROC;
+
m_serout_w_cb(offset, data);
m_SKSTAT |= SK_SEROUT;
/*
@@ -946,16 +995,16 @@ void pokey_device::write_internal(offs_t offset, uint8_t data)
* loaders from Ballblazer and Escape from Fractalus
* The real times are unknown
*/
- timer_set(attotime::from_usec(200), 3);
+ m_serout_ready_timer->adjust(attotime::from_usec(200));
/* 10 bits (assumption 1 start, 8 data and 1 stop bit) take how long? */
- timer_set(attotime::from_usec(2000), 4);// FUNC(pokey_serout_complete), 0, p);
+ m_serout_complete_timer->adjust(attotime::from_usec(2000));
break;
case IRQEN_C:
- LOG(("POKEY '%s' IRQEN $%02x\n", tag(), data));
+ LOG("%s: POKEY IRQEN $%02x\n", machine().describe_context(), data);
/* acknowledge one or more IRQST bits ? */
- if( m_IRQST & ~data )
+ if (m_IRQST & ~data)
{
/* reset IRQST bits that are masked now, except the SEROC bit (acid5200 pokey_seroc test) */
m_IRQST &= (IRQ_SEROC | data);
@@ -965,17 +1014,22 @@ void pokey_device::write_internal(offs_t offset, uint8_t data)
/* if SEROC irq is enabled trigger an irq (acid5200 pokey_seroc test) */
if (m_IRQEN & m_IRQST & IRQ_SEROC)
{
- if (!m_irq_f.isnull())
- m_irq_f(IRQ_SEROC);
+ LOG_IRQ("POKEY SEROC IRQ enabled\n");
+ m_irq_w_cb(ASSERT_LINE);
+ }
+ else if (!(m_IRQEN & m_IRQST))
+ {
+ LOG_IRQ("POKEY IRQs all cleared\n");
+ m_irq_w_cb(CLEAR_LINE);
}
break;
case SKCTL_C:
- if( data == m_SKCTL )
+ if (data == m_SKCTL)
return;
- LOG(("POKEY '%s' SKCTL $%02x\n", tag(), data));
+ LOG("%s: POKEY SKCTL $%02x\n", machine().describe_context(), data);
m_SKCTL = data;
- if( !(data & SK_RESET) )
+ if (!(data & SK_RESET))
{
write_internal(IRQEN_C, 0);
write_internal(SKREST_C, 0);
@@ -993,9 +1047,15 @@ void pokey_device::write_internal(offs_t offset, uint8_t data)
m_clock_cnt[0] = 0;
m_clock_cnt[1] = 0;
m_clock_cnt[2] = 0;
- m_old_raw_inval = true;
/* FIXME: Serial port reset ! */
}
+ if (!(data & SK_KEYSCAN))
+ {
+ m_SKSTAT &= ~SK_KEYBD;
+ m_kbd_cnt = 0;
+ m_kbd_state = 0;
+ }
+ m_old_raw_inval = true;
break;
}
@@ -1009,7 +1069,7 @@ void pokey_device::write_internal(offs_t offset, uint8_t data)
}
-WRITE_LINE_MEMBER( pokey_device::sid_w )
+void pokey_device::sid_w(int state)
{
if (state)
{
@@ -1023,7 +1083,7 @@ WRITE_LINE_MEMBER( pokey_device::sid_w )
void pokey_device::serin_ready(int after)
{
- timer_set(m_clock_period * after, 5, 0);
+ m_serin_ready_timer->adjust(m_clock_period * after, 0);
}
//-------------------------------------------------
@@ -1047,30 +1107,24 @@ inline void pokey_device::process_channel(int ch)
}
-void pokey_device::pokey_potgo(void)
+void pokey_device::pokey_potgo()
{
- int pot;
-
- if( (m_SKCTL & SK_RESET) == 0)
- return;
-
- LOG(("POKEY #%p pokey_potgo\n", (void *) this));
+ LOG("pokey_potgo\n");
m_ALLPOT = 0x00;
m_pot_counter = 0;
- for( pot = 0; pot < 8; pot++ )
+ for (int pot = 0; pot < 8; pot++)
{
m_POTx[pot] = 228;
- if( !m_pot_r_cb[pot].isnull() )
+ if (!m_pot_r_cb[pot].isunset())
{
int r = m_pot_r_cb[pot](pot);
- LOG(("POKEY %s pot_r(%d) returned $%02x\n", tag(), pot, r));
+ LOG("POKEY pot_r(%d) returned $%02x\n", pot, r);
if (r >= 228)
- {
r = 228;
- }
+
if (r == 0)
{
/* immediately set the ready - bit of m_ALLPOT
@@ -1108,12 +1162,12 @@ void pokey_device::vol_init()
}
r_chan[j] = 1.0 / rTot;
}
- if (VERBOSE)
+ if (VERBOSE & LOG_GENERAL)
for (int j=0; j<16; j++)
{
rTot = 1.0 / r_chan[j] + 3.0 / r_chan[0];
rTot = 1.0 / rTot;
- LOG(("%s: %3d - %4.3f\n", tag(), j, rTot / (rTot+pull_up)*4.75));
+ LOG("%3d - %4.3f\n", j, rTot / (rTot+pull_up)*4.75);
}
for (int j=0; j<0x10000; j++)
{
@@ -1128,58 +1182,54 @@ void pokey_device::vol_init()
}
-void pokey_device::poly_init_4_5(uint32_t *poly, int size, int xorbit, int invert)
+void pokey_device::poly_init_4_5(uint32_t *poly, int size)
{
+ LOG_POLY("poly %d\n", size);
+
int mask = (1 << size) - 1;
- int i;
uint32_t lfsr = 0;
- LOG_POLY(("poly %d\n", size));
- for( i = 0; i < mask; i++ )
+ int const xorbit = size - 1;
+ for (int i = 0; i < mask; i++)
{
- /* calculate next bit */
- int in = !((lfsr >> 0) & 1) ^ ((lfsr >> xorbit) & 1);
- lfsr = lfsr >> 1;
- lfsr = (in << (size-1)) | lfsr;
- *poly = lfsr ^ invert;
- LOG_POLY(("%05x: %02x\n", i, *poly));
+ lfsr = (lfsr << 1) | (~((lfsr >> 2) ^ (lfsr >> xorbit)) & 1);
+ *poly = lfsr & mask;
poly++;
}
}
void pokey_device::poly_init_9_17(uint32_t *poly, int size)
{
- int mask = (1 << size) - 1;
- int i;
- uint32_t lfsr =mask;
+ LOG_RAND("rand %d\n", size);
- LOG_RAND(("rand %d\n", size));
+ const uint32_t mask = util::make_bitmask<uint32_t>(size);
+ uint32_t lfsr = mask;
if (size == 17)
{
- for( i = 0; i < mask; i++ )
+ for (uint32_t i = 0; i < mask; i++)
{
- /* calculate next bit @ 7 */
- int in8 = ((lfsr >> 8) & 1) ^ ((lfsr >> 13) & 1);
- int in = (lfsr & 1);
+ // calculate next bit @ 7
+ const uint32_t in8 = BIT(lfsr, 8) ^ BIT(lfsr, 13);
+ const uint32_t in = BIT(lfsr, 0);
lfsr = lfsr >> 1;
lfsr = (lfsr & 0xff7f) | (in8 << 7);
lfsr = (in << 16) | lfsr;
*poly = lfsr;
- LOG_RAND(("%05x: %02x\n", i, *poly));
+ LOG_RAND("%05x: %02x\n", i, *poly);
poly++;
}
}
- else
+ else // size == 9
{
- for( i = 0; i < mask; i++ )
+ for (uint32_t i = 0; i < mask; i++)
{
- /* calculate next bit */
- int in = ((lfsr >> 0) & 1) ^ ((lfsr >> 5) & 1);
+ // calculate next bit
+ const uint32_t in = BIT(lfsr, 0) ^ BIT(lfsr, 5);
lfsr = lfsr >> 1;
lfsr = (in << 8) | lfsr;
*poly = lfsr;
- LOG_RAND(("%05x: %02x\n", i, *poly));
+ LOG_RAND("%05x: %02x\n", i, *poly);
poly++;
}
}
@@ -1189,22 +1239,20 @@ void pokey_device::poly_init_9_17(uint32_t *poly, int size)
char *pokey_device::audc2str(int val)
{
static char buff[80];
- if( val & NOTPOLY5 )
+ if (val & NOTPOLY5)
{
- if( val & PURE )
+ if (val & PURE)
strcpy(buff,"pure");
- else
- if( val & POLY4 )
+ else if (val & POLY4)
strcpy(buff,"poly4");
else
strcpy(buff,"poly9/17");
}
else
{
- if( val & PURE )
+ if (val & PURE)
strcpy(buff,"poly5");
- else
- if( val & POLY4 )
+ else if (val & POLY4)
strcpy(buff,"poly4+poly5");
else
strcpy(buff,"poly9/17+poly5");
@@ -1215,33 +1263,33 @@ char *pokey_device::audc2str(int val)
char *pokey_device::audctl2str(int val)
{
static char buff[80];
- if( val & POLY9 )
+ if (val & POLY9)
strcpy(buff,"poly9");
else
strcpy(buff,"poly17");
- if( val & CH1_HICLK )
+ if (val & CH1_HICLK)
strcat(buff,"+ch1hi");
- if( val & CH3_HICLK )
+ if (val & CH3_HICLK)
strcat(buff,"+ch3hi");
- if( val & CH12_JOINED )
+ if (val & CH12_JOINED)
strcat(buff,"+ch1/2");
- if( val & CH34_JOINED )
+ if (val & CH34_JOINED)
strcat(buff,"+ch3/4");
- if( val & CH1_FILTER )
+ if (val & CH1_FILTER)
strcat(buff,"+ch1filter");
- if( val & CH2_FILTER )
+ if (val & CH2_FILTER)
strcat(buff,"+ch2filter");
- if( val & CLK_15KHZ )
+ if (val & CLK_15KHZ)
strcat(buff,"+clk15");
return buff;
}
-pokey_device::pokey_channel::pokey_channel()
- : m_AUDF(0),
- m_AUDC(0),
- m_borrow_cnt(0),
- m_counter(0),
- m_output(0),
- m_filter_sample(0)
+pokey_device::pokey_channel::pokey_channel() :
+ m_AUDF(0),
+ m_AUDC(0),
+ m_borrow_cnt(0),
+ m_counter(0),
+ m_output(0),
+ m_filter_sample(0)
{
}