Added cycle exact potentiometer and keyboard support to pokey device [Couriersud].

The keyboard changes may break some MESS drivers. Please have a look at atari.c and bartop52.c for an example how the new implementation works.
This commit is contained in:
Couriersud 2012-05-25 23:47:28 +00:00
parent 4c5067b469
commit 35b59d7921
5 changed files with 287 additions and 277 deletions

View File

@ -13,6 +13,7 @@
* For more details read mame.txt that comes with MAME.
*
* 4.6:
* [1] 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
@ -71,7 +72,7 @@
#define POKEY_DEFAULT_GAIN (32767/11/4)
#define VERBOSE 0
#define VERBOSE 1
#define VERBOSE_SOUND 0
#define VERBOSE_TIMER 0
#define VERBOSE_POLY 0
@ -130,8 +131,8 @@
/* SKSTAT (R/D20F) */
#define SK_FRAME 0x80 /* serial framing error */
#define SK_OVERRUN 0x40 /* serial overrun error */
#define SK_KBERR 0x20 /* keyboard overrun error */
#define SK_KBERR 0x40 /* keyboard overrun error - pokey documentation states *some bit as IRQST */
#define SK_OVERRUN 0x20 /* serial overrun error - pokey documentation states *some bit as IRQST */
#define SK_SERIN 0x10 /* serial input high */
#define SK_SHIFT 0x08 /* shift key pressed */
#define SK_KEYBD 0x04 /* keyboard key pressed */
@ -143,6 +144,8 @@
#define SK_FM 0x08 /* FM 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 ? */
#define SK_DEBOUNCE 0x01 /* Debouncing ?*/
#define DIV_64 28 /* divisor for 1.78979 MHz clock to 63.9211 kHz */
#define DIV_15 114 /* divisor for 1.78979 MHz clock to 15.6999 kHz */
@ -156,7 +159,7 @@
#define CLK_28 1
#define CLK_114 2
static const int clock_divisors[3] = {1, 28, 114};
static const int clock_divisors[3] = {1, DIV_64, DIV_15};
@ -175,9 +178,7 @@ const device_type POKEYN = &device_creator<pokeyn_device>;
pokeyn_device::pokeyn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, POKEYN, "POKEYN", tag, owner, clock),
device_sound_interface(mconfig, *this),
#ifdef POKEY_EXEC_INTERFACE
device_execute_interface(mconfig, *this),
#endif
m_icount(0),
m_stream(NULL)
{
@ -215,14 +216,9 @@ void pokeyn_device::device_start()
* (takes two scanlines) but the result is not as accurate.
*/
m_ad_time_fast = (attotime::from_nsec(64000*2/228) * FREQ_17_EXACT) / clock();
m_ad_time_slow = (attotime::from_nsec(64000 ) * FREQ_17_EXACT) / clock();
/* initialize the poly counters */
poly_init_4_5(m_poly4, 4, 1, 0);
poly_init_4_5(m_poly5, 5, 2, 1);
//poly_init(m_poly9, 9, 8, 1, 0x00180);
//poly_init(m_poly17, 17,16, 1, 0x1c000);
/* initialize 9 / 17 arrays */
poly_init_9_17(m_poly9, 9);
@ -244,21 +240,21 @@ void pokeyn_device::device_start()
for (i=0; i<8; i++)
{
m_ptimer[i] = timer_alloc(2);
m_pot_r[i].resolve(m_intf.pot_r[i], *this);
}
m_allpot_r.resolve(m_intf.allpot_r, *this);
m_serin_r.resolve(m_intf.serin_r, *this);
m_serout_w.resolve(m_intf.serout_w, *this);
m_interrupt_cb = m_intf.interrupt_cb;
m_kbd_r.resolve(m_intf.kbd_r, *this);
m_stream = stream_alloc(0, 1, clock());
#ifdef POKEY_EXEC_INTERFACE
m_write_timer = timer_alloc(10); /* timer for sync operation */
timer_alloc(11);
#endif
timer_alloc(SYNC_WRITE); /* timer for sync operation */
timer_alloc(SYNC_NOOP);
timer_alloc(SYNC_POT);
timer_alloc(SYNC_SET_IRQST);
for (i=0; i<POKEY_CHANNELS; i++)
{
@ -278,6 +274,7 @@ void pokeyn_device::device_start()
save_item(NAME(m_p9));
save_item(NAME(m_p17));
save_item(NAME(m_clockmult));
save_item(NAME(m_pot_counter));
save_item(NAME(m_POTx));
save_item(NAME(m_AUDCTL));
save_item(NAME(m_ALLPOT));
@ -290,9 +287,7 @@ void pokeyn_device::device_start()
save_item(NAME(m_SKCTL));
// set our instruction counter
#ifdef POKEY_EXEC_INTERFACE
m_icountptr = &m_icount;
#endif
}
@ -332,16 +327,9 @@ void pokeyn_device::device_clock_changed()
void pokeyn_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
if (id == 2)
{
int pot = param;
LOG(("POKEY #%p POT%d triggers after %dus\n", this, pot, (int)(1000000 * m_ptimer[pot]->elapsed().as_double())));
m_ALLPOT &= ~(1 << pot); /* set the enabled timer irq status bits */
}
else if (id == 3)
switch (id)
{
case 3:
/* serout_ready_cb */
if( m_IRQEN & IRQ_SEROR )
{
@ -349,9 +337,8 @@ void pokeyn_device::device_timer(emu_timer &timer, device_timer_id id, int param
if( m_interrupt_cb )
(m_interrupt_cb)(this, IRQ_SEROR);
}
}
else if (id == 4)
{
break;
case 4:
/* serout_complete */
if( m_IRQEN & IRQ_SEROC )
{
@ -359,9 +346,8 @@ void pokeyn_device::device_timer(emu_timer &timer, device_timer_id id, int param
if( m_interrupt_cb )
(m_interrupt_cb)(this, IRQ_SEROC);
}
}
else if (id == 5)
{
break;
case 5:
/* serin_ready */
if( m_IRQEN & IRQ_SERIN )
{
@ -371,22 +357,29 @@ void pokeyn_device::device_timer(emu_timer &timer, device_timer_id id, int param
if( m_interrupt_cb )
(m_interrupt_cb)(this, IRQ_SERIN);
}
}
else if (id == 10)
{
offs_t offset = (param >> 8) & 0xff;
UINT8 data = param & 0xff;
write_internal(offset, data);
}
else if (id == 11)
{
break;
case SYNC_WRITE:
{
offs_t offset = (param >> 8) & 0xff;
UINT8 data = param & 0xff;
write_internal(offset, data);
}
break;
case SYNC_NOOP:
/* do nothing, caused by a forced resync */
}
else
break;
case SYNC_POT:
logerror("x %02x \n", (param & 0x20));
m_ALLPOT |= (param & 0xff);
break;
case SYNC_SET_IRQST:
m_IRQST |= (param & 0xff);
break;
default:
assert_always(FALSE, "Unknown id in pokey_device::device_timer");
}
}
#ifdef POKEY_EXEC_INTERFACE
void pokeyn_device::execute_run()
{
//bool check_debugger = ((device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) != 0);
@ -412,8 +405,6 @@ void pokeyn_device::device_timer(emu_timer &timer, device_timer_id id, int param
} while (m_icount > 0);
}
//{ m_icount = 0; } //printf("execute: %d\n", m_icount); m_icount = 0; }
#endif
//-------------------------------------------------
@ -421,6 +412,111 @@ void pokeyn_device::device_timer(emu_timer &timer, device_timer_id id, int param
// clock cycle.
//-------------------------------------------------
void pokeyn_device::step_keyboard()
{
if (++m_kbd_cnt > 63)
m_kbd_cnt = 0;
if (!m_kbd_r.isnull()) {
UINT8 ret = m_kbd_r(m_kbd_cnt);
switch (m_kbd_cnt)
{
case POK_KEY_BREAK:
if (ret & 2)
{
/* check if the break IRQ is enabled */
if( m_IRQEN & IRQ_BREAK )
{
/* set break IRQ status and call back the interrupt handler */
m_IRQST |= IRQ_BREAK;
if( m_interrupt_cb )
(*m_interrupt_cb)(this, IRQ_BREAK);
}
}
break;
case POK_KEY_SHIFT:
m_kbd_latch = (m_kbd_latch & 0xbf) | ((ret & 2) << 5);
if( m_kbd_latch & 0x40 )
m_SKSTAT |= SK_SHIFT;
else
m_SKSTAT &= ~SK_SHIFT;
/* FIXME: sync ? */
break;
case POK_KEY_CTRL:
m_kbd_latch = (m_kbd_latch & 0x7f) | ((ret & 2) << 6);
break;
}
switch (m_kbd_state)
{
case 0: /* waiting for key */
if (ret & 1)
{
m_kbd_latch = (m_kbd_latch & 0xc0) | m_kbd_cnt;
m_kbd_state++;
}
break;
case 1: /* waiting for key confirmation */
if ((m_kbd_latch & 0x3f) == m_kbd_cnt)
{
if (ret & 1)
{
m_KBCODE = m_kbd_latch;
m_SKSTAT |= SK_KEYBD;
if( m_IRQEN & IRQ_KEYBD )
{
/* last interrupt not acknowledged ? */
if( m_IRQST & IRQ_KEYBD )
m_SKSTAT |= SK_KBERR;
m_IRQST |= IRQ_KEYBD;
if( m_interrupt_cb )
(*m_interrupt_cb)(this, IRQ_KEYBD);
}
m_kbd_state++;
}
else
m_kbd_state = 0;
}
break;
case 2: /* waiting for release */
if ((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 (ret & 1)
m_kbd_state = 2;
else
{
m_SKSTAT &= ~SK_KEYBD;
m_kbd_state = 0;
}
}
break;
}
}
}
void pokeyn_device::step_pot()
{
int pot;
UINT8 upd = 0;
m_pot_counter++;
for (pot = 0; pot < 8; pot++)
{
if ((m_POTx[pot]<m_pot_counter) || (m_pot_counter == 228))
{
upd |= (1<<pot);
/* latching is emulated in read */
}
}
synchronize(SYNC_POT, upd);
}
/*
* http://www.atariage.com/forums/topic/3328-sio-protocol/page__st__100#entry1680190:
* I noticed that the Pokey counters have clocked carry (actually, "borrow") positions that delay the
@ -469,6 +565,14 @@ UINT32 pokeyn_device::step_one_clock(void)
if (!(m_AUDCTL & CH34_JOINED))
m_channel[CHAN4].inc_chan();
}
/* Potentiometer handling */
if ((clock_triggered[CLK_114] || (m_SKCTL & SK_PADDLE)) && (m_pot_counter < 228))
step_pot();
/* Keyboard */
if (clock_triggered[CLK_114] && (m_SKCTL & SK_KEYSCAN))
step_keyboard();
}
/* do CHAN2 before CHAN1 because CHAN1 may set borrow! */
@ -549,9 +653,6 @@ void pokeyn_device::sound_stream_update(sound_stream &stream, stream_sample_t **
while( samples > 0 )
{
#ifndef POKEY_EXEC_INTERFACE
m_output = step_one_clock();
#endif
/* store sum of output signals into the buffer */
*buffer++ = (m_output > 0x7fff) ? 0x7fff : m_output;
@ -573,33 +674,24 @@ UINT8 pokeyn_device::read(offs_t offset)
{
int data = 0, pot;
synchronize(11); /* force resync */
synchronize(SYNC_NOOP); /* force resync */
switch (offset & 15)
{
case POT0_C: case POT1_C: case POT2_C: case POT3_C:
case POT4_C: case POT5_C: case POT6_C: case POT7_C:
pot = offset & 7;
if( !m_pot_r[pot].isnull() )
if( m_ALLPOT & (1 << pot) )
{
/*
* If the conversion is not yet finished (ptimer running),
* get the current value by the linear interpolation of
* the final value using the elapsed time.
*/
if( m_ALLPOT & (1 << pot) )
{
data = m_ptimer[pot]->elapsed().attoseconds / ((m_SKCTL & SK_PADDLE) ? m_ad_time_fast : m_ad_time_slow).attoseconds;
LOG(("POKEY '%s' read POT%d (interpolated) $%02x\n", tag(), pot, data));
}
else
{
data = m_POTx[pot];
LOG(("POKEY '%s' read POT%d (final value) $%02x\n", tag(), pot, data));
}
/* we have a value measured */
data = m_POTx[pot];
LOG(("POKEY '%s' read POT%d (final value) $%02x\n", tag(), pot, data));
}
else
logerror("%s: warning - read '%s' POT%d\n", machine().describe_context(), tag(), pot);
//data = 0; //if (pot == 7) data = 1;
{
data = m_pot_counter;
LOG(("POKEY '%s' read POT%d (interpolated) $%02x\n", tag(), pot, data));
}
break;
case ALLPOT_C:
@ -619,10 +711,9 @@ UINT8 pokeyn_device::read(offs_t offset)
}
else
{
data = m_ALLPOT;
data = m_ALLPOT ^ 0xff;
LOG(("POKEY '%s' ALLPOT internal $%02x\n", tag(), data));
}
//data = 127;
break;
case KBCODE_C:
@ -633,13 +724,13 @@ UINT8 pokeyn_device::read(offs_t offset)
if( m_AUDCTL & POLY9 )
{
data = m_poly9[m_p9] & 0xff;
synchronize(11); /* force resync */
synchronize(SYNC_NOOP); /* force resync */
LOG_RAND(("POKEY '%s' rand9[$%05x]: $%02x\n", tag(), m_p9, data));
}
else
{
data = (m_poly17[m_p17] >> 8) & 0xff;
synchronize(11); /* force resync */
synchronize(SYNC_NOOP); /* force resync */
LOG_RAND(("POKEY '%s' rand17[$%05x]: $%02x\n", tag(), m_p17, data));
}
break;
@ -680,13 +771,7 @@ UINT8 pokeyn_device::read(offs_t offset)
void pokeyn_device::write(offs_t offset, UINT8 data)
{
#ifdef POKEY_EXEC_INTERFACE
synchronize(10, (offset<<8) | data);
#else
m_stream->update();
write_internal(offset, data);
#endif
synchronize(SYNC_WRITE, (offset<<8) | data);
}
WRITE8_MEMBER( pokeyn_device::write )
@ -850,109 +935,57 @@ void pokeyn_device::serin_ready(int after)
timer_set(m_clock_period * after, 5, 0);
}
void pokeyn_device::break_w(int shift)
{
if( shift ) /* shift code ? */
m_SKSTAT |= SK_SHIFT;
else
m_SKSTAT &= ~SK_SHIFT;
/* check if the break IRQ is enabled */
if( m_IRQEN & IRQ_BREAK )
{
/* set break IRQ status and call back the interrupt handler */
m_IRQST |= IRQ_BREAK;
if( m_interrupt_cb )
(*m_interrupt_cb)(this, IRQ_BREAK);
}
}
void pokeyn_device::kbcode_w(int kbcode, int make)
{
/* make code ? */
if( make )
{
m_KBCODE = kbcode;
m_SKSTAT |= SK_KEYBD;
if( kbcode & 0x40 ) /* shift code ? */
m_SKSTAT |= SK_SHIFT;
else
m_SKSTAT &= ~SK_SHIFT;
if( m_IRQEN & IRQ_KEYBD )
{
/* last interrupt not acknowledged ? */
if( m_IRQST & IRQ_KEYBD )
m_SKSTAT |= SK_KBERR;
m_IRQST |= IRQ_KEYBD;
if( m_interrupt_cb )
(*m_interrupt_cb)(this, IRQ_KEYBD);
}
}
else
{
m_KBCODE = kbcode;
m_SKSTAT &= ~SK_KEYBD;
}
}
//-------------------------------------------------
// private stuff
//-------------------------------------------------
inline void pokeyn_device::process_channel(int ch)
{
int toggle = 0;
if( (m_channel[ch].m_AUDC & NOTPOLY5) || (m_poly5[m_p5] & 1) )
if ((m_channel[ch].m_AUDC & NOTPOLY5) || (m_poly5[m_p5] & 1))
{
if( m_channel[ch].m_AUDC & PURE )
toggle = 1;
if (m_channel[ch].m_AUDC & PURE)
m_channel[ch].m_output ^= 1;
else if (m_channel[ch].m_AUDC & POLY4)
m_channel[ch].m_output = (m_poly4[m_p4] & 1);
else if (m_AUDCTL & POLY9)
m_channel[ch].m_output = (m_poly9[m_p9] & 1);
else
if( m_channel[ch].m_AUDC & POLY4 )
toggle = m_channel[ch].m_output == !(m_poly4[m_p4] & 1);
else
if( m_AUDCTL & POLY9 )
toggle = m_channel[ch].m_output == !(m_poly9[m_p9] & 1);
else
toggle = m_channel[ch].m_output == !(m_poly17[m_p17] & 1);
}
if( toggle )
{
m_channel[ch].m_output ^= 1;
m_channel[ch].m_output = (m_poly17[m_p17] & 1);
}
}
void pokeyn_device::pokey_potgo(void)
{
int pot;
LOG(("POKEY #%p pokey_potgo\n", this));
m_ALLPOT = 0xff;
m_ALLPOT = 0x00;
m_pot_counter = 0;
for( pot = 0; pot < 8; pot++ )
{
m_POTx[pot] = 0xff;
m_POTx[pot] = 228;
if( !m_pot_r[pot].isnull() )
{
int r = m_pot_r[pot](pot);
LOG(("POKEY %s pot_r(%d) returned $%02x\n", tag(), pot, r));
if( r != -1 )
if (r >= 228)
{
if (r > 228)
r = 228;
/* final value */
m_POTx[pot] = r;
m_ptimer[pot]->adjust(((m_SKCTL & SK_PADDLE) ? m_ad_time_fast : m_ad_time_slow) * r, pot);
r = 228;
}
if (r == 0)
{
/* immediately set the ready - bit of m_ALLPOT
* In this case, most likely no capacitor is connected
*/
m_ALLPOT |= (1<<pot);
}
/* final value */
m_POTx[pot] = r;
}
}
}
@ -1072,7 +1105,8 @@ pokeyn_device::pokey_channel::pokey_channel()
m_counter(0),
m_volume(0),
m_output(0),
m_filter_sample(0)
m_filter_sample(0),
m_div2(0)
{
}

View File

@ -21,8 +21,6 @@
#include "devlegcy.h"
#define POKEY_EXEC_INTERFACE
/* CONSTANT DEFINITIONS */
/* exact 1.79 MHz clock freq (of the Atari 800 that is) */
@ -47,6 +45,9 @@ struct _pokey_interface
devcb_read8 serin_r;
devcb_write8 serout_w;
void (*interrupt_cb)(pokeyn_device *device, int mask);
/* offset = k0 ... k5 , bit0: kr1, bit1: kr2 */
/* all are, in contrast to actual hardware, ACTIVE_HIGH */
devcb_read8 kbd_r;
};
@ -57,13 +58,19 @@ struct _pokey_interface
// ======================> pokey_device
class pokeyn_device : public device_t,
public device_sound_interface
#ifdef POKEY_EXEC_INTERFACE
,public device_execute_interface
#endif
public device_sound_interface,
public device_execute_interface,
public device_execute_state
{
public:
enum
{
POK_KEY_BREAK = 0x30,
POK_KEY_SHIFT = 0x20,
POK_KEY_CTRL = 0x00
};
enum
{
/* POKEY WRITE LOGICALS */
@ -103,6 +110,14 @@ public:
SKSTAT_C = 0x0F
};
enum /* sync-operations */
{
SYNC_NOOP = 11,
SYNC_SET_IRQST = 12,
SYNC_POT = 13,
SYNC_WRITE = 14
};
// construction/destruction
pokeyn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
@ -113,8 +128,6 @@ public:
void write(offs_t offset, UINT8 data);
void serin_ready(int after);
void break_w(int shift);
void kbcode_w(int kbcode, int make);
protected:
// device-level overrides
@ -127,9 +140,7 @@ protected:
// device_sound_interface overrides
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
#ifdef POKEY_EXEC_INTERFACE
virtual void execute_run();
#endif
// configuration state
pokey_interface m_intf;
@ -153,6 +164,7 @@ private:
UINT32 m_volume; /* channel volume - derived */
UINT8 m_output; /* channel output signal (1 active, 0 inactive) */
UINT8 m_filter_sample; /* high-pass filter sample */
UINT8 m_div2; /* division by 2 */
inline void sample(void) { m_filter_sample = m_output; }
inline void reset_channel(void) { m_counter = m_AUDF ^ 0xff; }
@ -165,7 +177,8 @@ private:
m_borrow_cnt = 3;
if (m_parent->m_IRQEN & m_INTMask)
{
m_parent->m_IRQST |= m_INTMask;
/* Exposed state has changed: This should only be updated after a resync ... */
m_parent->synchronize(SYNC_SET_IRQST, m_INTMask);
}
}
}
@ -184,6 +197,8 @@ private:
static const int POKEY_CHANNELS = 4;
UINT32 step_one_clock();
void step_keyboard();
void step_pot();
void poly_init_4_5(UINT32 *poly, int size, int xorbit, int invert);
void poly_init_9_17(UINT32 *poly, int size);
@ -208,16 +223,12 @@ private:
UINT32 m_p17; /* poly17 index */
UINT32 m_clockmult; /* clock multiplier */
emu_timer *m_ptimer[8]; /* pot timers */
#ifdef POKEY_EXEC_INTERFACE
emu_timer *m_write_timer; /* timer for sync operation */
#endif
devcb_resolved_read8 m_pot_r[8];
devcb_resolved_read8 m_allpot_r;
devcb_resolved_read8 m_serin_r;
devcb_resolved_write8 m_serout_w;
devcb_resolved_read8 m_kbd_r;
void (*m_interrupt_cb)(pokeyn_device *device, int mask);
UINT8 m_POTx[8]; /* POTx (R/D200-D207) */
@ -231,9 +242,12 @@ private:
UINT8 m_SKSTAT; /* SKSTAT (R/D20F) */
UINT8 m_SKCTL; /* SKCTL (W/D20F) */
UINT8 m_pot_counter;
UINT8 m_kbd_cnt;
UINT8 m_kbd_latch;
UINT8 m_kbd_state;
attotime m_clock_period;
attotime m_ad_time_fast;
attotime m_ad_time_slow;
UINT32 m_poly4[0x0f];
UINT32 m_poly5[0x1f];

View File

@ -114,6 +114,7 @@ static const pokey_interface atari_pokey_interface =
DEVCB_NULL,
DEVCB_NULL,
atari_interrupt_cb,
DEVCB_HANDLER(atari_a5200_keypads)
};
static MACHINE_CONFIG_START( a5200, bartop52_state )

View File

@ -33,8 +33,8 @@ MACHINE_START( atarixl );
void atari_interrupt_cb(pokeyn_device *device, int mask);
void a800_handle_keyboard(running_machine &machine);
void a5200_handle_keypads(running_machine &machine);
READ8_DEVICE_HANDLER(atari_a800_keyboard);
READ8_DEVICE_HANDLER(atari_a5200_keypads);
/* video */

View File

@ -16,9 +16,9 @@
#include "sound/dac.h"
#include "video/gtia.h"
#define VERBOSE_POKEY 0
#define VERBOSE_SERIAL 0
#define VERBOSE_TIMERS 0
#define VERBOSE_POKEY 1
#define VERBOSE_SERIAL 1
#define VERBOSE_TIMERS 1
static void a600xl_mmu(running_machine &machine, UINT8 new_mmu);
@ -155,62 +155,43 @@ void a600xl_mmu(running_machine &machine, UINT8 new_mmu)
**************************************************************/
static int atari_last;
void a800_handle_keyboard(running_machine &machine)
READ8_DEVICE_HANDLER(atari_a800_keyboard)
{
pokeyn_device *pokey = machine.device<pokeyn_device>("pokey");
int atari_code, count, ipt, i;
int ipt;
static const char *const tag[] = {
"keyboard_0", "keyboard_1", "keyboard_2", "keyboard_3",
"keyboard_4", "keyboard_5", "keyboard_6", "keyboard_7"
};
UINT8 ret = 0x00;
/* check keyboard */
for( i = 0; i < 8; i++ )
/* decode special */
switch (offset)
{
ipt = machine.root_device().ioport(tag[i])->read_safe(0);
if( ipt )
{
count = 0;
while(ipt / 2)
{
ipt = ipt/2;
count++;
}
atari_code = i*8 + count;
/* SHIFT */
if(machine.root_device().ioport("fake")->read_safe(0) & 0x01)
atari_code |= 0x40;
/* CTRL */
if(machine.root_device().ioport("fake")->read_safe(0) & 0x02)
atari_code |= 0x80;
if( atari_code != AKEY_NONE )
{
if( atari_code == atari_last )
return;
atari_last = atari_code;
if( (atari_code & 0x3f) == AKEY_BREAK )
{
pokey->break_w(atari_code & 0x40);
return;
}
pokey->kbcode_w(atari_code, 1);
return;
}
}
case pokeyn_device::POK_KEY_BREAK:
/* special case ... */
ret |= ((device->machine().root_device().ioport(tag[0])->read_safe(0) & 0x04) ? 0x02 : 0x00);
break;
case pokeyn_device::POK_KEY_CTRL:
/* CTRL */
ret |= ((device->machine().root_device().ioport("fake")->read_safe(0) & 0x02) ? 0x02 : 0x00);
break;
case pokeyn_device::POK_KEY_SHIFT:
/* SHIFT */
ret |= ((device->machine().root_device().ioport("fake")->read_safe(0) & 0x01) ? 0x02 : 0x00);
break;
}
/* remove key pressed status bit from skstat */
pokey->kbcode_w(AKEY_NONE, 0);
atari_last = AKEY_NONE;
/* return on BREAK key now! */
if (offset == AKEY_BREAK || offset == AKEY_NONE)
return ret;
/* decode regular key */
ipt = device->machine().root_device().ioport(tag[offset >> 3])->read_safe(0);
if (ipt & (1 << (offset & 0x07)))
ret |= 0x01;
return ret;
}
/**************************************************************
@ -242,60 +223,41 @@ void a800_handle_keyboard(running_machine &machine)
**************************************************************/
void a5200_handle_keypads(running_machine &machine)
READ8_DEVICE_HANDLER(atari_a5200_keypads)
{
pokeyn_device *pokey = downcast<pokeyn_device *>(machine.device("pokey"));
int atari_code, count, ipt, i;
int ipt;
static const char *const tag[] = { "keypad_0", "keypad_1", "keypad_2", "keypad_3" };
UINT8 ret = 0x00;
/* check keypad */
for( i = 0; i < 4; i++ )
/* decode special */
switch (offset)
{
ipt = machine.root_device().ioport(tag[i])->read_safe(0);
if( ipt )
{
count = 0;
while(ipt / 2)
{
ipt = ipt/2;
count++;
}
atari_code = i*4 + count;
if( atari_code == atari_last )
return;
atari_last = atari_code;
if( atari_code == 0 )
{
pokey->break_w(atari_code & 0x40);
return;
}
pokey->kbcode_w((atari_code << 1) | 0x21, 1);
return;
}
case pokeyn_device::POK_KEY_BREAK:
/* special case ... */
ret |= ((device->machine().root_device().ioport(tag[0])->read_safe(0) & 0x01) ? 0x02 : 0x00);
break;
case pokeyn_device::POK_KEY_CTRL:
case pokeyn_device::POK_KEY_SHIFT:
break;
}
/* check top button */
if ((machine.root_device().ioport("djoy_b")->read() & 0x10) == 0)
{
if (atari_last == 0xfe)
return;
pokey->kbcode_w(0x61, 1);
//pokey_break_w(pokey, 0x40);
atari_last = 0xfe;
return;
}
else if (atari_last == 0xfe)
pokey->kbcode_w(0x21, 1);
/* decode regular key */
/* if kr5 and kr0 not set just return */
if ((offset & 0x21) != 0x21)
return ret;
/* remove key pressed status bit from skstat */
pokey->kbcode_w(0xff, 0);
atari_last = 0xff;
offset = (offset >> 1) & 0x0f;
/* return on BREAK key now! */
if (offset == 0)
return ret;
ipt = device->machine().root_device().ioport(tag[offset >> 2])->read_safe(0);
if (ipt & (1 <<(offset & 0x03)))
ret |= 0x01;
return ret;
}
@ -310,7 +272,6 @@ static void pokey_reset(running_machine &machine)
{
pokeyn_device *pokey = downcast<pokeyn_device *>(machine.device("pokey"));
pokey->write(15,0);
atari_last = 0xff;
}