summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Ryan Holtz <ryan.holtz@arrowheadgs.com>2020-06-28 19:37:27 +0200
committer Ryan Holtz <ryan.holtz@arrowheadgs.com>2020-06-28 19:37:27 +0200
commitbc0b2c7b093ed57b8081c960c7e140f1a4c5192d (patch)
tree3aea60d3e527efbe1be45d287a695357e9c05fff
parent9c196024244f6b2152574a60b324a6e930250628 (diff)
-cmi2x: Numerous fixes, now boots into System Software V19, and plays audio badly.
-rw-r--r--src/mame/audio/cmi01a.cpp142
-rw-r--r--src/mame/audio/cmi01a.h16
-rw-r--r--src/mame/drivers/cmi.cpp234
-rw-r--r--src/mame/machine/cmi_mkbd.cpp60
-rw-r--r--src/mame/machine/cmi_mkbd.h1
5 files changed, 305 insertions, 148 deletions
diff --git a/src/mame/audio/cmi01a.cpp b/src/mame/audio/cmi01a.cpp
index 97e4655ce30..88246d809a8 100644
--- a/src/mame/audio/cmi01a.cpp
+++ b/src/mame/audio/cmi01a.cpp
@@ -8,7 +8,6 @@
#include "emu.h"
#include "audio/cmi01a.h"
-#include "machine/input_merger.h"
#define VERBOSE (0)
#include "logmacro.h"
@@ -21,6 +20,7 @@ DEFINE_DEVICE_TYPE(CMI01A_CHANNEL_CARD, cmi01a_device, "cmi_01a", "Fairlight CMI
cmi01a_device::cmi01a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, CMI01A_CHANNEL_CARD, tag, owner, clock)
, device_sound_interface(mconfig, *this)
+ , m_irq_merger(*this, "cmi01a_irq")
, m_pia(*this, "cmi01a_pia_%u", 0U)
, m_ptm(*this, "cmi01a_ptm")
, m_cmi02_pia(*this, "^cmi02_pia_%u", 1U)
@@ -37,41 +37,42 @@ void cmi01a_device::device_add_mconfig(machine_config &config)
m_pia[0]->writepb_handler().set(FUNC(cmi01a_device::rp_w));
m_pia[0]->ca2_handler().set(FUNC(cmi01a_device::pia_0_ca2_w));
m_pia[0]->cb2_handler().set(FUNC(cmi01a_device::pia_0_cb2_w));
- m_pia[0]->irqa_handler().set("cmi01a_irq", FUNC(input_merger_device::in_w<0>));
- m_pia[0]->irqb_handler().set("cmi01a_irq", FUNC(input_merger_device::in_w<1>));
+ m_pia[0]->irqa_handler().set(m_irq_merger, FUNC(input_merger_device::in_w<0>));
+ m_pia[0]->irqb_handler().set(m_irq_merger, FUNC(input_merger_device::in_w<1>));
PIA6821(config, m_pia[1], 0); // pia_cmi01a_2_config
m_pia[1]->readca1_handler().set(FUNC(cmi01a_device::zx_r));
m_pia[1]->readca2_handler().set(FUNC(cmi01a_device::eosi_r));
m_pia[1]->writepa_handler().set(FUNC(cmi01a_device::pia_1_a_w));
m_pia[1]->writepb_handler().set(FUNC(cmi01a_device::pia_1_b_w));
- m_pia[1]->irqa_handler().set("cmi01a_irq", FUNC(input_merger_device::in_w<2>));
- m_pia[1]->irqb_handler().set("cmi01a_irq", FUNC(input_merger_device::in_w<3>));
+ m_pia[1]->irqa_handler().set(m_irq_merger, FUNC(input_merger_device::in_w<2>));
+ m_pia[1]->irqb_handler().set(m_irq_merger, FUNC(input_merger_device::in_w<3>));
PTM6840(config, m_ptm, DERIVED_CLOCK(1, 1)); // ptm_cmi01a_config
m_ptm->o1_callback().set(FUNC(cmi01a_device::ptm_o1));
- m_ptm->irq_callback().set("cmi01a_irq", FUNC(input_merger_device::in_w<4>));
+ m_ptm->irq_callback().set(FUNC(cmi01a_device::ptm_irq));
- INPUT_MERGER_ANY_HIGH(config, "cmi01a_irq").output_handler().set(FUNC(cmi01a_device::cmi01a_irq));
+ INPUT_MERGER_ANY_HIGH(config, m_irq_merger).output_handler().set(FUNC(cmi01a_device::cmi01a_irq));
}
void cmi01a_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
- if (m_active && m_vol_latch)
+ if ((m_status & CHANNEL_STATUS_RUN) && m_vol_latch)
{
int length = samples;
- int seg_addr = m_segment_cnt & 0x7f;
+ int mask = (m_status & CHANNEL_STATUS_LOAD) ? 0x7fff : 0x7f;
+ int addr = m_segment_cnt;
+
uint8_t *wave_ptr = &m_wave_ram[m_segment_cnt & 0x3fff];
stream_sample_t *buf = outputs[0];
while (length--)
{
- *buf++ = wave_ptr[seg_addr];
- seg_addr = (seg_addr + 1) & 0x7f;
+ *buf++ = wave_ptr[addr++ & 0x3fff] << 7;
}
- m_segment_cnt = (m_segment_cnt & ~0x7f) | seg_addr;
+ m_segment_cnt = (m_segment_cnt & ~mask) | addr;
}
else
{
@@ -89,7 +90,10 @@ void cmi01a_device::device_start()
m_wave_ram = std::make_unique<uint8_t[]>(0x4000);
m_zx_timer = timer_alloc(TIMER_ZX);
+ m_eosi_timer = timer_alloc(TIMER_EOSI);
+
m_zx_timer->adjust(attotime::never);
+ m_eosi_timer->adjust(attotime::never);
m_stream = stream_alloc(0, 1, 44100);
@@ -110,18 +114,25 @@ void cmi01a_device::device_reset()
m_rp = 0;
m_ws = 0;
m_dir = 0;
+ m_pia0_cb2_state = 1;
m_freq = 0.0;
- m_active = false;
+ m_status = 0;
m_ptm_o1 = 0;
+
+ m_zx_timer->adjust(attotime::never);
+ m_eosi_timer->adjust(attotime::never);
}
WRITE_LINE_MEMBER( cmi01a_device::pia_0_ca2_w )
{
- // update_stream()
+ m_status &= ~CHANNEL_STATUS_LOAD;
+
if (!state)
{
+ m_status |= CHANNEL_STATUS_LOAD;
+
m_segment_cnt = 0x4000 | ((m_pia[0]->a_output() & 0x7f) << 7);
m_new_addr = 1;
m_pia[1]->cb1_w(1);
@@ -152,7 +163,7 @@ READ_LINE_MEMBER( cmi01a_device::tri_r )
{
bool top_terminal_count = (m_dir == ENV_DIR_UP && m_rp == 0);
bool bottom_terminal_count = (m_dir == ENV_DIR_DOWN && m_rp == 0xff);
- return (top_terminal_count || bottom_terminal_count) ? 1 : 0;
+ return (top_terminal_count || bottom_terminal_count) ? 0 : 1;
}
WRITE_LINE_MEMBER( cmi01a_device::cmi01a_irq )
@@ -167,9 +178,19 @@ void cmi01a_device::device_timer(emu_timer &timer, device_timer_id id, int param
case TIMER_ZX:
zx_timer_cb();
break;
+ case TIMER_EOSI:
+ eosi_timer_cb();
+ break;
}
}
+void cmi01a_device::eosi_timer_cb()
+{
+ m_pia[1]->cb1_w(0);
+
+// printf("End of sound\n");
+}
+
void cmi01a_device::zx_timer_cb()
{
/* Set ZX */
@@ -197,46 +218,71 @@ void cmi01a_device::zx_timer_cb()
void cmi01a_device::run_voice()
{
int val_a = m_pia[1]->a_output();
- int pitch = ((val_a & 3) << 8) | m_pia[1]->b_output();
+ int pitch = ((val_a & 3) << 8)
+ | m_pia[1]->b_output();
int o_val = (val_a >> 2) & 0xf;
+ LOG("CH%d running voice: PIA1 A output = %02x\n", m_channel, (uint8_t)val_a);
+ LOG("CH%d running voice: Pitch = %04x\n", m_channel, (uint16_t)pitch);
+ LOG("CH%d running voice: o_val = %x\n", m_channel, o_val);
+
int m_tune = m_cmi02_pia[0]->b_output();
- double mfreq = (double)(0xf00 | m_tune) * (MASTER_OSCILLATOR / 2.0 / 4096.0).dvalue();
+ LOG("CH%d running voice: Tuning = %02x\n", m_channel, (uint8_t)m_tune);
+ double mfreq = (double)(0xf00 | m_tune) * (MASTER_OSCILLATOR.dvalue() / 2.0) / 4096.0;
+ LOG("CH%d running voice: mfreq = %f (%03x * %f)\n", m_channel, mfreq, 0xf00 | m_tune, (MASTER_OSCILLATOR / 2.0 / 4096.0).dvalue());
- double cfreq = ((double)(0x800 | (pitch << 1))* mfreq) / 4096.0;
+ double cfreq = ((double)(0x800 | (pitch << 1)) * mfreq) / 4096.0;
+ LOG("CH%d running voice: cfreq = %f (%04x * %f) / 4096.0\n", m_channel, mfreq, 0x800 | (pitch << 1), mfreq, cfreq);
-// if (cfreq > 0.0)
+ if (cfreq > MASTER_OSCILLATOR.dvalue())
{
- /* Octave register enabled? */
- if (!(o_val & 0x8))
- cfreq /= 2 << ((7 ^ o_val) & 7);
+ LOG("CH%d Ignoring voice run due to excessive frequency\n");
+ return;
+ }
+
+ LOG("CH%d Running voice\n", m_channel);
+ /* Octave register enabled? */
+ if (!(o_val & 0x8))
+ cfreq /= 2 << ((7 ^ o_val) & 7);
+
+ cfreq /= 16.0f;
- cfreq /= 16.0f;
+ m_freq = cfreq;
- m_freq = cfreq;
+ LOG("CH%d running voice: Final freq: %f\n", m_channel, m_freq);
- m_stream->set_sample_rate(cfreq);
+ m_stream->set_sample_rate(cfreq);
- // Set timers and things?
- attotime zx_period = attotime::from_ticks(64, cfreq);
- m_zx_timer->adjust(zx_period, 0, zx_period);
+ // Set timers and things?
+ attotime zx_period = attotime::from_ticks(64, cfreq);
+ m_zx_timer->adjust(zx_period, 0, zx_period);
- m_active = true;
+ if (m_status & CHANNEL_STATUS_LOAD)
+ {
+ int samples = 0x4000 - (m_segment_cnt & 0x3fff);
+ m_eosi_timer->adjust(attotime::from_ticks(samples, cfreq));
}
}
WRITE_LINE_MEMBER( cmi01a_device::pia_0_cb2_w )
{
+ int old_state = m_pia0_cb2_state;
+ m_pia0_cb2_state = state;
+ LOG("CH%d PIA0 CB2: %d\n", m_channel, state);
+
//streams_update();
/* RUN */
- if (state)
+ if (!old_state && m_pia0_cb2_state)
{
- m_segment_cnt = 0x4000 | ((m_pia[0]->a_output() & 0x7f) << 7);
- m_new_addr = 1;
+ m_status |= CHANNEL_STATUS_RUN;
- /* Clear /EOSI */
-// pia6821_cb1_w(card->pia[1], 0, 1);
+ /* Only reset address counter if /LOAD not asserted */
+ if ((m_status & CHANNEL_STATUS_LOAD) == 0)
+ {
+ m_segment_cnt = 0x4000 | ((m_pia[0]->a_output() & 0x7f) << 7);
+ m_new_addr = 1;
+ }
/* Clear ZX */
m_pia[1]->ca1_w(0);
@@ -250,8 +296,11 @@ WRITE_LINE_MEMBER( cmi01a_device::pia_0_cb2_w )
run_voice();
}
- else
+
+ if (old_state && !m_pia0_cb2_state)
{
+ m_status &= ~CHANNEL_STATUS_RUN;
+
/* Clear /EOSI */
m_pia[1]->cb1_w(1);
@@ -260,8 +309,7 @@ WRITE_LINE_MEMBER( cmi01a_device::pia_0_cb2_w )
m_ptm->set_g3(1);
m_zx_timer->adjust(attotime::never);
- m_active = false;
- m_zx_flag = 0; // TEST
+ m_eosi_timer->adjust(attotime::never);
m_zx_ff = 0;
}
@@ -291,6 +339,11 @@ void cmi01a_device::update_wave_addr(int inc)
/* Zero crossing interrupt is a pulse */
}
+WRITE_LINE_MEMBER( cmi01a_device::ptm_irq )
+{
+ m_irq_merger->in_w<4>(state);
+}
+
WRITE_LINE_MEMBER( cmi01a_device::ptm_o1 )
{
m_ptm_o1 = state;
@@ -303,7 +356,7 @@ READ_LINE_MEMBER( cmi01a_device::eosi_r )
READ_LINE_MEMBER( cmi01a_device::zx_r )
{
- return m_segment_cnt & 0x40;
+ return (m_segment_cnt & 0x40) >> 6;
}
void cmi01a_device::write(offs_t offset, uint8_t data)
@@ -337,10 +390,12 @@ void cmi01a_device::write(offs_t offset, uint8_t data)
break;
case 0x8: case 0x9: case 0xa: case 0xb:
+ LOG("CH%d PIA0 Write: %d = %02x\n", m_channel, offset & 3, data);
m_pia[0]->write(offset & 3, data);
break;
case 0xc: case 0xd: case 0xe: case 0xf:
+ LOG("CH%d PIA1 Write: %d = %02x\n", m_channel, (BIT(offset, 0) << 1) | BIT(offset, 1), data);
m_pia[1]->write((BIT(offset, 0) << 1) | BIT(offset, 1), data);
break;
@@ -351,7 +406,10 @@ void cmi01a_device::write(offs_t offset, uint8_t data)
int a1 = (m_ptm_o1 && BIT(offset, 3)) || (!BIT(offset, 3) && BIT(offset, 2));
int a2 = BIT(offset, 1);
- //osd_printf_debug("CH%d PTM W: [%x] = %02x\n", m_channel, (a2 << 2) | (a1 << 1) | a0, data);
+ if ((offset == 5 || offset == 7) && (data < 0x30))
+ data = 0xff;
+
+ LOG("CH%d PTM Write: %d = %02x\n", m_channel, (a2 << 2) | (a1 << 1) | a0, data);
m_ptm->write((a2 << 2) | (a1 << 1) | a0, data);
break;
}
@@ -395,21 +453,23 @@ uint8_t cmi01a_device::read(offs_t offset)
case 0x8: case 0x9: case 0xa: case 0xb:
data = m_pia[0]->read(offset & 3);
+ LOG("CH%d PIA0 Read: %d = %02x\n", m_channel, offset & 3, data);
break;
case 0xc: case 0xd: case 0xe: case 0xf:
data = m_pia[1]->read((BIT(offset, 0) << 1) | BIT(offset, 1));
+ LOG("CH%d PIA1 Read: %d = %02x\n", m_channel, (BIT(offset, 0) << 1) | BIT(offset, 1), data);
break;
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
{
int a0 = offset & 1;
- int a1 = ((m_ptm_o1 && BIT(offset, 3)) || (!BIT(offset, 3) && BIT(offset, 2))) ? 1 : 0;
+ int a1 = (m_ptm_o1 && BIT(offset, 3)) || (!BIT(offset, 3) && BIT(offset, 2));
int a2 = BIT(offset, 1);
data = m_ptm->read((a2 << 2) | (a1 << 1) | a0);
- //osd_printf_debug("CH%d PTM R: [%x] %02x\n", m_channel, (a2 << 2) | (a1 << 1) | a0, data);
+ LOG("CH%d PTM Read: %d = %02x\n", m_channel, (a2 << 2) | (a1 << 1) | a0, data);
break;
}
diff --git a/src/mame/audio/cmi01a.h b/src/mame/audio/cmi01a.h
index d6faf8ebe37..6a11f655e63 100644
--- a/src/mame/audio/cmi01a.h
+++ b/src/mame/audio/cmi01a.h
@@ -11,10 +11,13 @@
#include "machine/6821pia.h"
#include "machine/6840ptm.h"
+#include "machine/input_merger.h"
#define ENV_DIR_DOWN 0
#define ENV_DIR_UP 1
+#define CHANNEL_STATUS_LOAD 1
+#define CHANNEL_STATUS_RUN 2
class cmi01a_device : public device_t, public device_sound_interface {
public:
@@ -41,7 +44,9 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
static const device_timer_id TIMER_ZX = 0;
+ static const device_timer_id TIMER_EOSI = 1;
+ required_device<input_merger_device> m_irq_merger;
required_device_array<pia6821_device, 2> m_pia;
required_device<ptm6840_device> m_ptm;
@@ -53,6 +58,7 @@ private:
DECLARE_WRITE_LINE_MEMBER(cmi01a_irq);
void zx_timer_cb();
+ void eosi_timer_cb();
void run_voice();
void update_wave_addr(int inc);
@@ -61,18 +67,21 @@ private:
uint8_t m_zx_flag;
uint8_t m_zx_ff;
+ emu_timer * m_eosi_timer;
+
std::unique_ptr<uint8_t[]> m_wave_ram;
uint16_t m_segment_cnt;
uint8_t m_new_addr; // Flag
uint8_t m_env_dir_ctrl;
uint8_t m_vol_latch;
uint8_t m_flt_latch;
- uint8_t m_rp;
- uint8_t m_ws;
+ uint8_t m_rp;
+ uint8_t m_ws;
int m_dir;
+ int m_pia0_cb2_state;
double m_freq;
- bool m_active;
+ uint8_t m_status;
int m_ptm_o1;
@@ -90,6 +99,7 @@ private:
void pia_1_b_w(uint8_t data);
DECLARE_WRITE_LINE_MEMBER( ptm_o1 );
+ DECLARE_WRITE_LINE_MEMBER( ptm_irq );
};
// device type definition
diff --git a/src/mame/drivers/cmi.cpp b/src/mame/drivers/cmi.cpp
index e12e5ae3fb6..5da94aebe20 100644
--- a/src/mame/drivers/cmi.cpp
+++ b/src/mame/drivers/cmi.cpp
@@ -12,7 +12,6 @@
To do:
* V12 system software reports that it can't load MIDI support and then hangs.
- * V19 system software simply hangs.
Information from:
@@ -161,7 +160,7 @@
static const int ch_int_levels[8] =
{
- 0xc ^ 7, 0x8 ^ 7, 0xd ^ 7, 0x9 ^ 7, 0xe ^ 7, 0xa ^ 7, 0xf ^ 7, 0xb ^ 7
+ 12 ^ 7, 8 ^ 7, 13 ^ 7, 9 ^ 7, 14 ^ 7, 10 ^ 7, 15 ^ 7, 11 ^ 7
};
#define IRQ_PERRINT_LEVEL (0 ^ 7)
@@ -251,6 +250,9 @@ public:
template<int cpunum> uint8_t perr_r(offs_t offset);
template<int cpunum> void perr_w(offs_t offset, uint8_t data);
+ uint16_t m_aic_ad565_in[16];
+ uint8_t m_aic_mux_latch;
+
uint8_t aic_ad574_r();
template<int Dac> void aic_dac_w(uint8_t data);
void aic_mux_latch_w(uint8_t data);
@@ -319,7 +321,6 @@ public:
DECLARE_READ_LINE_MEMBER( cmi02_pia2_ca1_r );
DECLARE_WRITE_LINE_MEMBER( cmi02_pia2_cb2_w );
- // ???
uint8_t cmi07_r();
void cmi07_w(uint8_t data);
@@ -397,8 +398,7 @@ private:
// Video
void hblank();
- void update_video_pos(int y, int x, int byte_size);
- void video_write(int offset);
+ template <int Y, int X, bool ByteSize> void update_video_pos();
// Floppy
void dma_fdc_rom();
@@ -409,6 +409,7 @@ private:
uint8_t *m_q133_rom;
uint16_t m_int_state[2];
+ uint8_t m_lp_int;
uint8_t m_hp_int;
std::unique_ptr<uint8_t[]> m_shared_ram;
std::unique_ptr<uint8_t[]> m_scratch_ram[2];
@@ -461,7 +462,7 @@ uint32_t cmi_state::screen_update_cmi2x(screen_device &screen, bitmap_rgb32 &bit
{
const pen_t *pen = m_palette->pens();
uint8_t y_scroll = m_q219_pia->a_output();
- uint8_t invert = (!BIT(m_q219_pia->b_output(), 3)) & 1;
+ uint8_t invert = BIT(~m_q219_pia->b_output(), 3);
for (int y = cliprect.min_y; y <= cliprect.max_y; ++y)
{
@@ -502,12 +503,8 @@ void cmi_state::hblank()
if (v == m_lp_y_port->read())
{
- if (_touch)
- m_q219_b_touch = 1 << 5;
- else
- m_q219_b_touch = 0;
-
- m_q219_pia->ca1_w(_touch ? 1 : 0);
+ m_q219_b_touch = _touch ? 0 : (1 << 5);
+ m_q219_pia->ca1_w(_touch ? 0 : 1);
if (!_touch || !_tfh)
{
@@ -528,11 +525,24 @@ void cmi_state::hblank()
}
-void cmi_state::update_video_pos(int y, int x, int byte_size)
+template void cmi_state::update_video_pos< 0, 0, false>();
+template void cmi_state::update_video_pos< 0, 1, false>();
+template void cmi_state::update_video_pos< 0, -1, false>();
+template void cmi_state::update_video_pos< 0, 0, true>();
+template void cmi_state::update_video_pos< 1, 0, false>();
+template void cmi_state::update_video_pos< 1, 1, false>();
+template void cmi_state::update_video_pos< 1, -1, false>();
+template void cmi_state::update_video_pos< 1, 0, true>();
+template void cmi_state::update_video_pos<-1, 0, false>();
+template void cmi_state::update_video_pos<-1, 1, false>();
+template void cmi_state::update_video_pos<-1, -1, false>();
+template void cmi_state::update_video_pos<-1, 0, true>();
+
+template <int Y, int X, bool ByteSize> void cmi_state::update_video_pos()
{
uint8_t *video_addr = &m_video_ram[m_y_pos * (512 / 8) + (m_x_pos / 8)];
- if (byte_size)
+ if (ByteSize)
{
*video_addr = m_video_data;
}
@@ -544,35 +554,8 @@ void cmi_state::update_video_pos(int y, int x, int byte_size)
*video_addr |= m_video_data & bit_mask;
}
- if (y > 0)
- m_y_pos = (m_y_pos + 1) & 0xff;
- else if (y < 0)
- m_y_pos = (m_y_pos - 1) & 0xff;
-
- if (x > 0)
- m_x_pos = (m_x_pos + 1) & 0x1ff;
- else if (x < 0)
- m_x_pos = (m_x_pos - 1) & 0x1ff;
-}
-
-void cmi_state::video_write(int offset)
-{
- switch (offset)
- {
- case 0x0: update_video_pos( 0, 0, 0); break;
- case 0x1: update_video_pos( 0, 1, 0); break;
- case 0x2: update_video_pos( 0, -1, 0); break;
- case 0x3: update_video_pos( 0, 0, 1); break;
- case 0x4: update_video_pos( 1, 0, 0); break;
- case 0x5: update_video_pos( 1, 1, 0); break;
- case 0x6: update_video_pos( 1, -1, 0); break;
- case 0x7: update_video_pos( 1, 0, 1); break;
- case 0x8: update_video_pos(-1, 0, 0); break;
- case 0x9: update_video_pos(-1, 1, 0); break;
- case 0xa: update_video_pos(-1, -1, 0); break;
- case 0xb: update_video_pos(-1, 0, 1); break;
-// default: osd_printf_debug("Video Write %x %x\n", offset, m_video_data);
- }
+ m_y_pos = (m_y_pos + Y) & 0xff;
+ m_x_pos = (m_x_pos + X) & 0x1ff;
}
uint8_t cmi_state::video_r(offs_t offset)
@@ -582,7 +565,23 @@ uint8_t cmi_state::video_r(offs_t offset)
m_video_data = m_video_ram[m_y_pos * (512 / 8) + (m_x_pos / 8)];
- video_write(offset);
+ switch (offset & 0x0f)
+ {
+ case 0x0: update_video_pos< 0, 0, false>(); break;
+ case 0x1: update_video_pos< 0, 1, false>(); break;
+ case 0x2: update_video_pos< 0, -1, false>(); break;
+ case 0x3: update_video_pos< 0, 0, true>(); break;
+ case 0x4: update_video_pos< 1, 0, false>(); break;
+ case 0x5: update_video_pos< 1, 1, false>(); break;
+ case 0x6: update_video_pos< 1, -1, false>(); break;
+ case 0x7: update_video_pos< 1, 0, true>(); break;
+ case 0x8: update_video_pos<-1, 0, false>(); break;
+ case 0x9: update_video_pos<-1, 1, false>(); break;
+ case 0xa: update_video_pos<-1, -1, false>(); break;
+ case 0xb: update_video_pos<-1, 0, true>(); break;
+ default: break;
+ }
+
return m_video_data;
}
@@ -603,7 +602,23 @@ uint8_t cmi_state::pia_q219_b_r()
void cmi_state::video_w(offs_t offset, uint8_t data)
{
m_video_data = data;
- video_write(offset);
+
+ switch (offset & 0x0f)
+ {
+ case 0x0: update_video_pos< 0, 0, false>(); break;
+ case 0x1: update_video_pos< 0, 1, false>(); break;
+ case 0x2: update_video_pos< 0, -1, false>(); break;
+ case 0x3: update_video_pos< 0, 0, true>(); break;
+ case 0x4: update_video_pos< 1, 0, false>(); break;
+ case 0x5: update_video_pos< 1, 1, false>(); break;
+ case 0x6: update_video_pos< 1, -1, false>(); break;
+ case 0x7: update_video_pos< 1, 0, true>(); break;
+ case 0x8: update_video_pos<-1, 0, false>(); break;
+ case 0x9: update_video_pos<-1, 1, false>(); break;
+ case 0xa: update_video_pos<-1, -1, false>(); break;
+ case 0xb: update_video_pos<-1, 0, true>(); break;
+ default: break;
+ }
}
void cmi_state::vscroll_w(uint8_t data)
@@ -689,8 +704,7 @@ template<int cpunum> uint8_t cmi_state::vector_r(offs_t offset)
template<int cpunum> uint8_t cmi_state::map_r()
{
- uint8_t data = (m_cpu_active_space[1] << 2) | (m_cpu_active_space[0] << 1) | cpunum;
- return data;
+ return (m_cpu_active_space[1] << 2) | (m_cpu_active_space[0] << 1) | cpunum;
}
template<int cpunum> void cmi_state::map_w(uint8_t data)
@@ -706,7 +720,7 @@ template<int cpunum> uint8_t cmi_state::irq_ram_r(offs_t offset)
if (m_m6809_bs_hack_cnt[cpunum] > 0)
{
m_m6809_bs_hack_cnt[cpunum]--;
- LOG("CPU%d IRQ vector byte %d (offset %d): %02x\n", cpunum, 1 - m_m6809_bs_hack_cnt[cpunum], offset, m_irq_address[cpunum][offset]);
+ LOG("CPU%d IRQ vector byte %d (offset %d): %02x\n", cpunum + 1, 1 - m_m6809_bs_hack_cnt[cpunum], offset, m_irq_address[cpunum][offset]);
return m_irq_address[cpunum][offset];
}
return m_scratch_ram[cpunum][0xf8 + offset];
@@ -761,7 +775,6 @@ void cmi_state::cpufunc_w(uint8_t data)
case 0: set_interrupt(cpunum, IRQ_IPI2_LEVEL, bit ? ASSERT_LINE : CLEAR_LINE);
break;
case 2: // TODO: Hardware trace
- osd_printf_debug("TODO: Hardware trace %02x\n", data);
break;
case 4: m_cpu_map_switch[cpunum] = bit;
break;
@@ -919,7 +932,7 @@ static INPUT_PORTS_START( cmi2x )
PORT_BIT( 0xffff, VBLANK_START/2, IPT_LIGHTGUN_Y) PORT_NAME ("Lightpen Y") PORT_MINMAX(0, VBLANK_START - 1) PORT_SENSITIVITY(50) PORT_CROSSHAIR(Y, 1.0, 0.0, 0)
PORT_START("LP_TOUCH")
- PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME ( "Lightpen Touch" ) PORT_CODE( MOUSECODE_BUTTON1 )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME ( "Lightpen Touch" ) PORT_CODE( MOUSECODE_BUTTON1 )
INPUT_PORTS_END
bool cmi_state::map_is_active(int cpunum, int map, uint8_t *map_info)
@@ -1029,6 +1042,12 @@ void cmi_state::cmi07_w(uint8_t data)
{
LOG("%s: cmi07_w: %02x\n", machine().describe_context(), data);
+ if (true)
+ {
+ return;
+ }
+
+ const uint8_t prev = m_cmi07_ctrl;
m_cmi07_ctrl = data;
m_cmi07cpu->set_input_line(INPUT_LINE_RESET, BIT(data, 0) ? CLEAR_LINE : ASSERT_LINE);
@@ -1040,6 +1059,10 @@ void cmi_state::cmi07_w(uint8_t data)
uint8_t map_info = (m_cpu_active_space[0] == MAPPING_A) ? m_map_sel[MAPSEL_P1_A] : m_map_sel[MAPSEL_P1_B];
update_address_space(0, map_info);
+ /* CPU 2 space is untouched by this update */
+ if (BIT(prev & data, 7))
+ return;
+
map_info = (m_cpu_active_space[1] == MAPPING_A) ? m_map_sel[MAPSEL_P2_A] : m_map_sel[MAPSEL_P2_B];
update_address_space(1, map_info);
}
@@ -1340,31 +1363,39 @@ uint8_t cmi_state::cmi02_r(offs_t offset)
}
else
{
- LOG("%s: CMI02 R: %x\n", machine().describe_context(), offset);
-
+ uint8_t data = 0;
switch (offset)
{
case 0x20: case 0x21: case 0x22: case 0x23:
- return m_cmi02_pia[0]->read(offset & 3);
+ data = m_cmi02_pia[0]->read(offset & 3);
+ LOG("%s: CMI02 PIA 1 read (offset %d): %02x\n", machine().describe_context(), offset & 3, data);
+ return data;
case 0x26:
m_maincpu2->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
/* LS123 one-shot with 10n and 150k */
m_jam_timeout_timer->adjust(attotime::from_usec(675));
+ LOG("%s: CMI02 Jam Timeout timer trigger read: %02x\n", machine().describe_context(), 0xff);
return 0xff;
case 0x27:
m_maincpu2->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
+ LOG("%s: CMI02 CPU2 Unhalt read: %02x\n", machine().describe_context(), 0xff);
return 0xff;
case 0x28: case 0x29: case 0x2a: case 0x2b:
- return m_cmi02_pia[1]->read(offset & 3);
+ data = m_cmi02_pia[1]->read(offset & 3);
+ LOG("%s: CMI02 PIA 2 read (offset %d): %02x\n", machine().describe_context(), offset & 3, data);
+ return data;
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
- return m_cmi02_ptm->read(offset & 7);
+ data = m_cmi02_ptm->read(offset & 7);
+ LOG("%s: CMI02 PTM read (offset %d): %02x\n", machine().describe_context(), offset & 7, data);
+ return data;
default:
- return 0;
+ LOG("%s: CMI02 Unknown read (offset %02x): %02x\n", machine().describe_context(), offset, 0x00);
+ return data;
}
}
}
@@ -1383,44 +1414,44 @@ void cmi_state::cmi02_w(offs_t offset, uint8_t data)
}
else
{
- if (offset == 0x30)
- {
- LOG("%s: CMI02 W: %x %x, clearing IRQ merger bit 1\n", machine().describe_context(), offset, data);
- }
- else
- {
- LOG("%s: CMI02 W: %x %x\n", machine().describe_context(), offset, data);
- }
-
switch (offset)
{
case 0x20: case 0x21: case 0x22: case 0x23:
+ LOG("%s: CMI02 PIA 1 write (offset %d): %02x\n", machine().describe_context(), offset & 3, data);
m_cmi02_pia[0]->write(offset & 3, data);
break;
case 0x28: case 0x29: case 0x2a: case 0x2b:
+ LOG("%s: CMI02 PIA 2 write (offset %d): %02x\n", machine().describe_context(), offset & 3, data);
m_cmi02_pia[1]->write(offset & 3, data);
break;
case 0x30:
- m_maincpu1_irq_merger->in_w<1>(0);
+ LOG("%s: CMI02 PICU 3 B/SGS write (clearing main CPU IRQ merger, clearing high-prio IRQ): %02x\n", machine().describe_context(), data);
m_hp_int = 0;
+ m_maincpu1_irq_merger->in_w<1>(0);
+ //if (m_lp_int == 0)
+ // m_maincpu1->set_input_line(M6809_IRQ_LINE, CLEAR_LINE);
m_i8214[2]->b_sgs_w(~(data & 0xf));
break;
case 0x31: case 0x32:
+ LOG("%s: CMI02 INTP1 %s write: %02x\n", machine().describe_context(), (offset & 2) ? "clear" : "set", data);
set_interrupt(0, IRQ_INTP1_LEVEL, (offset & 2) ? CLEAR_LINE : ASSERT_LINE);
break;
case 0x33: case 0x34:
+ LOG("%s: CMI02 INTP2 %s write: %02x\n", machine().describe_context(), (offset & 4) ? "clear" : "set", data);
set_interrupt(1, IRQ_INTP2_LEVEL, (offset & 4) ? CLEAR_LINE : ASSERT_LINE);
break;
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ LOG("%s: CMI02 PTM write (offset %d): %02x\n", machine().describe_context(), offset & 7, data);
m_cmi02_ptm->write(offset & 7, data);
break;
default:
+ LOG("%s: CMI02 Unknown write (offset %02x): %02x\n", machine().describe_context(), offset, data);
break;
}
}
@@ -1441,8 +1472,11 @@ void cmi_state::install_video_ram(int cpunum)
void cmi_state::i8214_cpu1_w(uint8_t data)
{
- LOG("%s: i8214_cpu1_w, clearing IRQ merger bit 0: %02x\n", machine().describe_context(), data);
+ //LOG("%s: i8214_cpu1_w, clearing IRQ merger bit 0: %02x\n", machine().describe_context(), data);
m_maincpu1_irq_merger->in_w<0>(0);
+ m_lp_int = 0;
+ //if (m_hp_int == 0)
+ // m_maincpu1->set_input_line(M6809_IRQ_LINE, CLEAR_LINE);
m_i8214[0]->b_sgs_w(~(data & 0xf));
}
@@ -1469,7 +1503,6 @@ template<int cpunum> void cmi_state::perr_w(offs_t offset, uint8_t data)
m_q256_ram[BIT(ram_index, 7)][(ram_index & 0x7f) * PAGE_SIZE + offset % PAGE_SIZE] = data;
}
-// TODO: replace with share()
uint8_t cmi_state::shared_ram_r(offs_t offset)
{
return m_shared_ram[offset];
@@ -1477,15 +1510,16 @@ uint8_t cmi_state::shared_ram_r(offs_t offset)
void cmi_state::shared_ram_w(offs_t offset, uint8_t data)
{
- //logerror("shared_ram_w: %04x = %02x\n", 0xfe00 + offset, data);
m_shared_ram[offset] = data;
}
uint8_t cmi_state::aic_ad574_r()
{
- LOG("%s: AIC AD574 read\n", machine().describe_context());
- // To Do
- return 0;
+ const bool adca = BIT(m_aic_mux_latch, 5); // false - MSB, true - LSB
+ const uint16_t val = m_aic_ad565_in[m_aic_mux_latch & 0x07];
+ const uint8_t data = adca ? ((uint8_t)val) : (val >> 8);
+ LOG("%s: AIC AD574 read: %02x\n", machine().describe_context(), data);
+ return data;
}
template<int Dac> void cmi_state::aic_dac_w(uint8_t data)
@@ -1497,20 +1531,35 @@ template<int Dac> void cmi_state::aic_dac_w(uint8_t data)
void cmi_state::aic_mux_latch_w(uint8_t data)
{
LOG("%s: AIC mux latch write: %02x\n", machine().describe_context(), data);
- set_interrupt(CPU_1, IRQ_AIC_LEVEL, (BIT(data, 6) && BIT(data, 7)) ? ASSERT_LINE : CLEAR_LINE);
- // To Do
+ set_interrupt(CPU_1, IRQ_AIC_LEVEL, BIT(data, 7) ? ASSERT_LINE : CLEAR_LINE);
+ if (data & 0x07)
+ {
+ m_aic_mux_latch = data;
+ }
+ else
+ {
+ m_aic_mux_latch &= 0x07;
+ m_aic_mux_latch |= data & 0xf8;
+ }
+ if (!BIT(data, 6))
+ {
+ LOG("%s: ADCR is 0, initiating ADC conversion request\n", machine().describe_context());
+ m_aic_ad565_in[m_aic_mux_latch & 0x07] = 0;
+ }
}
void cmi_state::aic_ad565_msb_w(uint8_t data)
{
- LOG("%s: AIC AD565 MSB write: %02x\n", machine().describe_context(), data);
- // To Do
+ m_aic_ad565_in[m_aic_mux_latch & 0x07] &= 0x00ff;
+ m_aic_ad565_in[m_aic_mux_latch & 0x07] |= (uint16_t)data << 8;
+ LOG("%s: AIC AD565 MSB write: %02x, input %04x\n", machine().describe_context(), data, m_aic_ad565_in[m_aic_mux_latch & 0x07]);
}
void cmi_state::aic_ad565_lsb_w(uint8_t data)
{
LOG("%s: AIC AD565 LSB write: %02x\n", machine().describe_context(), data);
- // To Do
+ m_aic_ad565_in[m_aic_mux_latch & 0x07] &= 0xff00;
+ m_aic_ad565_in[m_aic_mux_latch & 0x07] |= data;
}
void cmi_state::install_peripherals(int cpunum)
@@ -1540,7 +1589,7 @@ void cmi_state::install_peripherals(int cpunum)
space->install_readwrite_handler(0xfc8c, 0xfc8f, read8sm_delegate(*m_q133_acia[3], FUNC(mos6551_device::read)), write8sm_delegate(*m_q133_acia[3], FUNC(mos6551_device::write)));
space->install_readwrite_handler(0xfc90, 0xfc97, read8sm_delegate(*m_q133_ptm, FUNC(ptm6840_device::read)), write8sm_delegate(*m_q133_ptm, FUNC(ptm6840_device::write)));
- space->install_write_handler(0xfca0, 0xfca0, write8smo_delegate(*this, FUNC(cmi_state::midi_latch_w)));
+ //space->install_write_handler(0xfca0, 0xfca0, write8smo_delegate(*this, FUNC(cmi_state::midi_latch_w)));
space->install_readwrite_handler(0xfcbc, 0xfcbc, read8smo_delegate(*this, FUNC(cmi_state::cmi07_r)), write8smo_delegate(*this, FUNC(cmi_state::cmi07_w)));
@@ -1603,6 +1652,10 @@ IRQ_CALLBACK_MEMBER( cmi_state::cpu1_interrupt_callback )
LOG("%s: CPU1 interrupt, will be pushing address %02x%02x\n", machine().describe_context(), m_irq_address[CPU_1][0], m_irq_address[CPU_1][1]);
}
+ else
+ {
+ LOG("%s: Some other CPU1 interrupt, line %d\n", irqline);
+ }
return 0;
}
@@ -1646,9 +1699,6 @@ void cmi_state::set_interrupt(int cpunum, int level, int state)
{
m_i8214[1]->r_all_w(~m_int_state[cpunum]);
}
-
- //i8214_device *i8214 = ((cpunum == CPU_2) ? m_i8214[1] : (level < 8 ? m_i8214[2] : m_i8214[0]));
- //i8214->r_w(level & 7, state ? 0 : 1);
}
WRITE_LINE_MEMBER( cmi_state::maincpu1_irq_w )
@@ -1668,7 +1718,8 @@ WRITE_LINE_MEMBER( cmi_state::i8214_1_int_w )
LOG("%s: i8214_1_int_w %d%s\n", machine().describe_context(), state, state ? ", setting IRQ merger bit 0" : "");
if (state)
{
- m_hp_int = 0;
+ m_lp_int = 1;
+ //m_maincpu1->set_input_line(M6809_IRQ_LINE, ASSERT_LINE);
m_maincpu1_irq_merger->in_w<0>(state);
}
}
@@ -1688,6 +1739,9 @@ WRITE_LINE_MEMBER( cmi_state::i8214_3_int_w )
m_hp_int = 1;
m_maincpu1_irq_merger->in_w<1>(state);
}
+ //m_hp_int = 1;
+ //m_maincpu1->set_input_line(M6809_IRQ_LINE, ASSERT_LINE);
+ //m_maincpu1->set_input_line(M6809_IRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
}
@@ -1814,11 +1868,24 @@ void cmi_state::machine_reset()
m_cmi07_ctrl = 0;
m_cmi07cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
+ // SMIDI
+ m_midicpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
+
m_cmi02_ptm_irq = 0;
+ m_cmi02_ptm->set_c2(1);
+ m_cmi02_ptm->set_g1(0);
+ m_cmi02_ptm->set_g2(0);
+ m_cmi02_ptm->set_g3(0);
m_m6809_bs_hack_cnt[0] = 0;
m_m6809_bs_hack_cnt[1] = 0;
memset(m_map_sel, 0, 16);
+
+ for (int i = 0; i < 4; i++)
+ {
+ m_q133_acia[i]->write_dsr(0);
+ m_q133_acia[i]->write_dcd(0);
+ }
}
void cmi_state::machine_start()
@@ -1947,7 +2014,8 @@ void cmi_state::cmi2x(machine_config &config)
m_cmi02_pia[1]->readca1_handler().set(FUNC(cmi_state::cmi02_pia2_ca1_r));
m_cmi02_pia[1]->cb2_handler().set(FUNC(cmi_state::cmi02_pia2_cb2_w));
- PTM6840(config, m_cmi02_ptm, SYSTEM_CAS_CLOCK); // ptm_cmi02_config, clock is incorrect
+ PTM6840(config, m_cmi02_ptm, SYSTEM_CAS_CLOCK);
+ m_cmi02_ptm->set_external_clocks(0, 0, 0);
m_cmi02_ptm->o2_callback().set(FUNC(cmi_state::cmi02_ptm_o2));
m_cmi02_ptm->irq_callback().set(FUNC(cmi_state::cmi02_ptm_irq));
diff --git a/src/mame/machine/cmi_mkbd.cpp b/src/mame/machine/cmi_mkbd.cpp
index b8bbd84e6b0..2128f88c5b1 100644
--- a/src/mame/machine/cmi_mkbd.cpp
+++ b/src/mame/machine/cmi_mkbd.cpp
@@ -56,6 +56,7 @@ cmi_music_keyboard_device::cmi_music_keyboard_device(const machine_config &mconf
, m_dp3(*this, "dp3")
, m_keypad_a_port(*this, "KEYPAD_A")
, m_keypad_b_port(*this, "KEYPAD_B")
+ , m_analog(*this, "ANALOG")
, m_key_mux_ports{ { *this, "KEY_%u_0", 0 }, { *this, "KEY_%u_1", 0 }, { *this, "KEY_%u_2", 0 }, { *this, "KEY_%u_3", 0 } }
, m_digit(*this, "digit%u", 0U)
{
@@ -128,20 +129,6 @@ void cmi_music_keyboard_device::cmi10_u20_a_w(u8 data)
void cmi_music_keyboard_device::cmi10_u20_b_w(u8 data)
{
- // connected to alphanumeric display control lines
- u8 const addr = bitswap<2>(data, 0, 1);
-
- m_dp1->ce_w(BIT(data, 6));
- m_dp1->cu_w(BIT(data, 7));
- m_dp1->addr_w(addr);
-
- m_dp2->ce_w(BIT(data, 4));
- m_dp2->cu_w(BIT(data, 5));
- m_dp2->addr_w(addr);
-
- m_dp3->ce_w(BIT(data, 2));
- m_dp3->cu_w(BIT(data, 3));
- m_dp3->addr_w(addr);
}
READ_LINE_MEMBER( cmi_music_keyboard_device::cmi10_u20_cb1_r )
@@ -159,10 +146,30 @@ READ_LINE_MEMBER( cmi_music_keyboard_device::cmi10_u20_cb1_r )
WRITE_LINE_MEMBER( cmi_music_keyboard_device::cmi10_u20_cb2_w )
{
- // connected to alphanumeric display write strobe
+ uint8_t data = m_cmi10_pia_u20->a_output() & 0x7f;
+ uint8_t b_port = m_cmi10_pia_u20->b_output();
+ int addr = (BIT(b_port, 0) << 1) | BIT(b_port, 1);
+
+ /* DP1 */
+ m_dp1->ce_w(BIT(b_port, 6));
+ m_dp1->cu_w(BIT(b_port, 7));
m_dp1->wr_w(state);
+ m_dp1->addr_w(addr);
+ m_dp1->data_w(data);
+
+ /* DP2 */
+ m_dp2->ce_w(BIT(b_port, 4));
+ m_dp2->cu_w(BIT(b_port, 5));
m_dp2->wr_w(state);
+ m_dp2->addr_w(addr);
+ m_dp2->data_w(data);
+
+ /* DP3 */
+ m_dp3->ce_w(BIT(b_port, 2));
+ m_dp3->cu_w(BIT(b_port, 3));
m_dp3->wr_w(state);
+ m_dp3->addr_w(addr);
+ m_dp3->data_w(data);
}
template <unsigned N> void cmi_music_keyboard_device::update_dp(offs_t offset, u16 data)
@@ -194,9 +201,9 @@ u8 cmi_music_keyboard_device::cmi10_u21_a_r()
u8 keyval;
int state = 1;
- if (mux == 0 && key == 3)
+ if (module == 1 && mux == 2 && key == 3)
{
- //keyval = input_port_read(device->machine, "ANALOG");
+ keyval = m_analog->read();
/* Unpressed */
if (keyval <= 0)
@@ -234,6 +241,18 @@ u8 cmi_music_keyboard_device::cmi10_u21_a_r()
data |= BIT(keyval, key) << module;
}
+ /* Now do KD7 */
+ {
+ int bit = 0;
+
+ if (BIT(sel, 3))
+ bit = BIT(m_keypad_a_port->read(), sel & 7);
+ else if (!BIT(sel, 4))
+ bit = BIT(m_keypad_b_port->read(), sel & 7);
+
+ data |= (bit && BIT(sel, 7)) << 7;
+ }
+
return data;
#endif
}
@@ -243,13 +262,9 @@ WRITE_LINE_MEMBER( cmi_music_keyboard_device::kbd_acia_int )
m_kbd_acia_irq = state;
if (m_kbd_acia_irq)
- {
m_cpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
- }
else if (!m_cmi_acia_irq)
- {
m_cpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
- }
}
WRITE_LINE_MEMBER( cmi_music_keyboard_device::cmi_acia_int )
@@ -435,6 +450,9 @@ static INPUT_PORTS_START(cmi_music_keyboard)
PORT_START("KEY_2_3")
PORT_BIT(0xff, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F6")
+
+ PORT_START("ANALOG")
+ PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_MINMAX(0, 128) PORT_SENSITIVITY(100) PORT_KEYDELTA(50)
INPUT_PORTS_END
ioport_constructor cmi_music_keyboard_device::device_input_ports() const
diff --git a/src/mame/machine/cmi_mkbd.h b/src/mame/machine/cmi_mkbd.h
index dd5a87e3b57..653083ce939 100644
--- a/src/mame/machine/cmi_mkbd.h
+++ b/src/mame/machine/cmi_mkbd.h
@@ -76,6 +76,7 @@ private:
required_ioport m_keypad_a_port;
required_ioport m_keypad_b_port;
+ required_ioport m_analog;
required_ioport_array<3> m_key_mux_ports[4];