From 068b396753bebed772444469d58beb5c4dd78e44 Mon Sep 17 00:00:00 2001 From: MooglyGuy Date: Fri, 15 Jul 2022 18:53:48 +0200 Subject: fairlight/cmi.cpp: Fairlight CMI IIx audio improvements: (#10086) [Ryan Holtz] * fairlight/cmi01a.cpp: Nearly complete rewrite of CMI-01A "Channel Card" emulation. * machine/6840ptm.cpp: Fixed a number of bugs in the 6840 PTM emulation. --- src/devices/machine/6821pia.cpp | 9 +- src/devices/machine/6840ptm.cpp | 305 ++++++++++---- src/devices/machine/6840ptm.h | 12 +- src/mame/fairlight/cmi.cpp | 363 +++++++--------- src/mame/fairlight/cmi01a.cpp | 904 +++++++++++++++++++++------------------- src/mame/fairlight/cmi01a.h | 231 +++++----- src/mame/fairlight/cmi_mkbd.cpp | 259 +++++++----- src/mame/fairlight/cmi_mkbd.h | 89 ++++ 8 files changed, 1253 insertions(+), 919 deletions(-) diff --git a/src/devices/machine/6821pia.cpp b/src/devices/machine/6821pia.cpp index 9d6e063c938..2b32eb164ff 100644 --- a/src/devices/machine/6821pia.cpp +++ b/src/devices/machine/6821pia.cpp @@ -13,13 +13,14 @@ // MACROS //************************************************************************** -#define LOG_GENERAL 0x01 -#define LOG_SETUP 0x02 -#define LOG_CA1 0x08 +#define LOG_SETUP (1 << 1U) +#define LOG_CA1 (1 << 2U) //#define VERBOSE (LOG_SETUP | LOG_GENERAL | LOG_CA1) //#define LOG_OUTPUT_STREAM std::cout +#define VERBOSE (0) + #include "logmacro.h" #define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__) #define LOGCA1(...) LOGMASKED(LOG_CA1, __VA_ARGS__) @@ -843,7 +844,7 @@ void pia6821_device::write(offs_t offset, uint8_t data) break; case 0x01: - control_a_w( data); + control_a_w(data); break; case 0x02: diff --git a/src/devices/machine/6840ptm.cpp b/src/devices/machine/6840ptm.cpp index 8d0039e2a92..390669d0b1c 100644 --- a/src/devices/machine/6840ptm.cpp +++ b/src/devices/machine/6840ptm.cpp @@ -49,7 +49,6 @@ #define VERBOSE (0) #include "logmacro.h" - /*************************************************************************** LOCAL VARIABLES ***************************************************************************/ @@ -122,6 +121,7 @@ void ptm6840_device::device_start() save_item(NAME(m_enabled)); save_item(NAME(m_external_clock)); save_item(NAME(m_counter)); + save_item(NAME(m_disable_time)); save_item(NAME(m_latch)); save_item(NAME(m_hightime)); } @@ -149,17 +149,19 @@ void ptm6840_device::device_reset() { m_counter[i] = 0xffff; m_latch[i] = 0xffff; - m_output[i] = 0; + m_disable_time[i] = attotime::never; + m_output[i] = false; + m_clk[i] = false; m_fired[i] = 0; m_enabled[i] = 0; - m_mode[i] = 0; + m_mode[i] = 0; } } void ptm6840_device::device_resolve_objects() { for (int i = 0; i < 3; i++) - m_gate[i] = 0; + m_gate[i] = false; } @@ -208,18 +210,17 @@ void ptm6840_device::subtract_from_counter(int counter, int count) // Count the clocks word -= count; - // loop while we're less than zero - while (word < 0) + // if we're less than zero + if (word < 0) { - // Borrow from the MSB - word += m_latch[counter] + 1; - // We've expired timeout(counter); } - - // Store the result - m_counter[counter] = word; + else + { + // Store the result + m_counter[counter] = word; + } } if (m_enabled[counter]) @@ -237,6 +238,9 @@ void ptm6840_device::subtract_from_counter(int counter, int count) { duration *= m_t3_divisor; } + + duration += attotime::from_ticks(2, clock()); + m_timer[counter]->adjust(duration, counter); } } @@ -305,21 +309,26 @@ void ptm6840_device::update_interrupts() // compute_counter - Compute Counter //------------------------------------------------- -uint16_t ptm6840_device::compute_counter( int counter ) const +uint16_t ptm6840_device::compute_counter(int counter) const { - double clk; + uint32_t clk; // If there's no timer, return the count if (!m_enabled[counter]) { - LOGMASKED(LOG_COUNTERS, "Timer #%d read counter: %d\n", counter + 1, m_counter[counter]); + LOGMASKED(LOG_COUNTERS, "Timer #%d read counter: %04x\n", counter + 1, m_counter[counter]); return m_counter[counter]; } + else if (m_control_reg[0] & RESET_TIMERS) + { + // If we're held in reset, return the latch value, as it's what is meaningful + return m_latch[counter]; + } // determine the clock frequency for this timer if (m_control_reg[counter] & INTERNAL_CLK_EN) { - clk = static_cast(clock()); + clk = clock(); } else { @@ -330,10 +339,25 @@ uint16_t ptm6840_device::compute_counter( int counter ) const { clk /= m_t3_divisor; } - LOGMASKED(LOG_COUNTERS, "Timer #%d %s clock freq %f \n", counter + 1, (m_control_reg[counter] & INTERNAL_CLK_EN) ? "internal" : "external", clk); + LOGMASKED(LOG_COUNTERS, "Timer #%d %s clock freq %d\n", counter + 1, (m_control_reg[counter] & INTERNAL_CLK_EN) ? "internal" : "external", clk); // See how many are left - int remaining = (m_timer[counter]->remaining() * clk).as_double(); + attotime remaining_time = m_timer[counter]->remaining(); + if (remaining_time.is_never()) + { + if (m_disable_time[counter].is_never()) + { + return m_counter[counter]; + } + remaining_time = m_disable_time[counter]; + } + attotime e_time = attotime::from_ticks(2, clock()); + int remaining = 0; + if (remaining_time >= e_time) + { + remaining_time -= e_time; + remaining = remaining_time.as_ticks(clk); + } // Adjust the count for dual byte mode if (m_control_reg[counter] & COUNT_MODE_8BIT) @@ -344,7 +368,7 @@ uint16_t ptm6840_device::compute_counter( int counter ) const remaining = (msb << 8) | lsb; } - LOGMASKED(LOG_COUNTERS, "Timer #%d read counter: %d\n", counter + 1, remaining); + LOGMASKED(LOG_COUNTERS, "Timer #%d read counter: %04x\n", counter + 1, remaining); return remaining; } @@ -356,16 +380,11 @@ uint16_t ptm6840_device::compute_counter( int counter ) const void ptm6840_device::reload_count(int idx) { - double clk; - // Copy the latched value in m_counter[idx] = m_latch[idx]; - // If reset is held, don't start counting - if (m_control_reg[0] & RESET_TIMERS) - return; - // Determine the clock frequency for this timer + double clk; if (m_control_reg[idx] & INTERNAL_CLK_EN) { clk = static_cast (clock()); @@ -385,28 +404,31 @@ void ptm6840_device::reload_count(int idx) count = 0xff; else count = ((count >> 8) + 1) * ((count & 0xff) + 1); - - } - else - { - count = count + 1; } m_fired[idx] = 0; - if ((m_mode[idx] == 4) || (m_mode[idx] == 6)) + const bool one_shot_mode = m_mode[idx] == 4 || m_mode[idx] == 6; + if (one_shot_mode) { - m_output[idx] = 1; - m_out_cb[idx](m_output[idx]); + m_output[idx] = false; + if (!(m_control_reg[idx] & COUNT_OUT_EN)) + { + m_out_cb[idx](0); + } + else + { + m_out_cb[idx](m_output[idx]); + } } // Set the timer - LOGMASKED(LOG_COUNTERS, "Timer #%d reload_count: clock = %f count = %d\n", idx + 1, clk, count); + LOGMASKED(LOG_COUNTERS, "Timer #%d init_timer: clock = %f count = %04x\n", idx + 1, clk, count); if (clk == 0.0) { m_enabled[idx] = 0; - m_timer[idx]->enable(false); + m_timer[idx]->adjust(attotime::never); } else { @@ -417,11 +439,23 @@ void ptm6840_device::reload_count(int idx) duration *= m_t3_divisor; } - LOGMASKED(LOG_COUNTERS, "Timer #%d reload_count: output = %f\n", idx + 1, duration.as_double()); + duration += attotime::from_ticks(2, clock()); + + LOGMASKED(LOG_COUNTERS, "Timer #%d init_timer: output = %f\n", idx + 1, duration.as_double()); m_enabled[idx] = 1; - m_timer[idx]->adjust(duration, idx); - m_timer[idx]->enable(true); + + const bool one_shot_mode = m_mode[idx] == 4 || m_mode[idx] == 6; + const bool gated = (!one_shot_mode && m_gate[idx]) || (m_control_reg[0] & RESET_TIMERS); + if (gated) + { + m_disable_time[idx] = duration; + m_timer[idx]->adjust(attotime::never); + } + else + { + m_timer[idx]->adjust(duration, idx); + } } } @@ -438,25 +472,28 @@ uint8_t ptm6840_device::read(offs_t offset) switch ( offset ) { case PTM_6840_CTRL1: - { val = 0; break; - } case PTM_6840_STATUS: - { LOGMASKED(LOG_STATUS, "%s: Status read = %04X\n", machine().describe_context(), m_status_reg); m_status_read_since_int |= m_status_reg & 0x07; val = m_status_reg; break; - } + + case PTM_6840_LSB1: + case PTM_6840_LSB2: + case PTM_6840_LSB3: + val = m_lsb_buffer; + LOGMASKED(LOG_COUNTERS, "%s: Counter LSB read = %02x\n", machine().describe_context(), val); + break; case PTM_6840_MSBBUF1: case PTM_6840_MSBBUF2: case PTM_6840_MSBBUF3: { int idx = (offset - 2) / 2; - int result = compute_counter(idx); + uint16_t result = compute_counter(idx); // Clear the interrupt if the status has been read if (m_status_read_since_int & (1 << idx)) @@ -465,26 +502,16 @@ uint8_t ptm6840_device::read(offs_t offset) update_interrupts(); } - m_lsb_buffer = result & 0xff; - - LOGMASKED(LOG_COUNTERS, "%s: Counter %d read = %04X\n", machine().describe_context(), idx + 1, result >> 8); val = result >> 8; - break; - } + m_lsb_buffer = (uint8_t)result; - case PTM_6840_LSB1: - case PTM_6840_LSB2: - case PTM_6840_LSB3: - { - val = m_lsb_buffer; + LOGMASKED(LOG_COUNTERS, "%s: Counter %d MSB read = %02x\n", machine().describe_context(), idx + 1, val); break; } default: - { val = 0; break; - } } return val; @@ -510,8 +537,11 @@ void ptm6840_device::write(offs_t offset, uint8_t data) LOGMASKED(LOG_CONTROL, "Control register #%d selected\n", idx + 1); LOGMASKED(LOG_CONTROL, "operation mode = %s\n", opmode[m_mode[idx]]); - LOGMASKED(LOG_CONTROL, "value = %04X\n", m_control_reg[idx]); + LOGMASKED(LOG_CONTROL, "value = %02x\n", m_control_reg[idx]); LOGMASKED(LOG_CONTROL, "t3divisor = %d\n", m_t3_divisor); + LOGMASKED(LOG_CONTROL, "irq/output/int = %d/%d/%d\n", BIT(m_control_reg[idx], 6), BIT(m_control_reg[idx], 7), BIT(m_control_reg[idx], 1)); + LOGMASKED(LOG_CONTROL, "latch = %04x\n", m_latch[idx]); + LOGMASKED(LOG_CONTROL, "counter = %04x\n", m_counter[idx]); if (diffs & INTERRUPT_EN) update_interrupts(); @@ -528,12 +558,18 @@ void ptm6840_device::write(offs_t offset, uint8_t data) // Holding reset down if (data & RESET_TIMERS) { + m_status_reg = 0; + m_status_read_since_int = 0; + update_interrupts(); LOGMASKED(LOG_RESETS, "Timer reset\n"); for (int i = 0; i < 3; i++) { - m_timer[i]->enable(false); + m_timer[i]->adjust(attotime::never); m_enabled[i] = 0; - m_hightime[idx] = false; + m_hightime[i] = false; + reload_count(i); + m_output[i] = false; + m_out_cb[i](m_output[i]); } } // Releasing reset @@ -541,8 +577,13 @@ void ptm6840_device::write(offs_t offset, uint8_t data) { for (int i = 0; i < 3; i++) { - m_hightime[idx] = false; + m_hightime[i] = false; reload_count(i); + if (!m_disable_time[i].is_never() && m_timer[i]->remaining().is_never() && ((m_control_reg[i] & INTERNAL_CLK_EN) || m_external_clock[i] != 0.0)) + { + m_timer[i]->adjust(m_disable_time[i], i); + m_disable_time[i] = attotime::never; + } } } @@ -554,7 +595,54 @@ void ptm6840_device::write(offs_t offset, uint8_t data) if (diffs & INTERNAL_CLK_EN) { m_hightime[idx] = false; - reload_count(idx); + if (!(m_control_reg[0] & RESET_TIMERS)) + { + double divisor = idx == 2 ? m_t3_divisor : 1.0; + double clk = (m_control_reg[idx] & INTERNAL_CLK_EN ? static_cast(clock()) : m_external_clock[idx]) / divisor; + + if (clk == 0.0) + { + // Temporarily restore the old control value to retrieve the current counter value + m_control_reg[idx] ^= diffs; + m_counter[idx] = compute_counter(idx); + m_control_reg[idx] = data; + + m_enabled[idx] = 0; + m_timer[idx]->adjust(attotime::never); + } + else + { + attotime duration = attotime::from_hz(clk); + u16 updated_count = m_counter[idx]; + if (m_control_reg[idx] & INTERNAL_CLK_EN && m_external_clock[idx] == 0) + { + duration *= updated_count; + } + else + { + // Temporarily restore the old control value to retrieve the current counter value + m_control_reg[idx] ^= diffs; + updated_count = compute_counter(idx); + duration *= updated_count; + m_control_reg[idx] = data; + } + + duration += attotime::from_ticks(2, clock()); + + m_enabled[idx] = 1; + + const bool one_shot_mode = m_mode[idx] == 4 || m_mode[idx] == 6; + const bool gated = !one_shot_mode && m_gate[idx]; + if (gated) + { + m_timer[idx]->adjust(attotime::never); + } + else + { + m_disable_time[idx] = duration; + } + } + } } break; } @@ -621,7 +709,7 @@ TIMER_CALLBACK_MEMBER(ptm6840_device::timeout) } else { - m_output[param] = m_output[param] ^ 1; + m_output[param] = !m_output[param]; m_out_cb[param](m_output[param]); } LOGMASKED(LOG_TIMEOUTS, "%6.6f: **ptm6840 t%d output %d **\n", machine().time().as_double(), param + 1, m_output[param]); @@ -631,7 +719,7 @@ TIMER_CALLBACK_MEMBER(ptm6840_device::timeout) case 6: if (!m_fired[param]) { - m_output[param] = 1; + m_output[param] = true; LOGMASKED(LOG_TIMEOUTS, "**ptm6840 t%d output %d **\n", param + 1, m_output[param]); m_out_cb[param](m_output[param]); @@ -646,6 +734,10 @@ TIMER_CALLBACK_MEMBER(ptm6840_device::timeout) break; } } + else + { + m_out_cb[param](0); + } m_enabled[param]= 0; reload_count(param); } @@ -657,13 +749,24 @@ TIMER_CALLBACK_MEMBER(ptm6840_device::timeout) void ptm6840_device::set_gate(int idx, int state) { - if ((m_mode[idx] & 1) == 0) + const bool one_shot_mode = m_mode[idx] == 4 || m_mode[idx] == 6; + if (state == 0 && m_gate[idx]) { - if (state == 0 && m_gate[idx]) + if (!(m_control_reg[0] & RESET_TIMERS)) { m_hightime[idx] = false; reload_count(idx); } + if (!m_disable_time[idx].is_never() && ((m_control_reg[idx] & INTERNAL_CLK_EN) || m_external_clock[idx] != 0.0)) + { + m_timer[idx]->adjust(m_disable_time[idx], idx); + m_disable_time[idx] = attotime::never; + } + } + else if (state == 1 && !m_gate[idx] && !one_shot_mode) // Gate disable is ignored in one-shot mode + { + m_disable_time[idx] = m_timer[idx]->remaining(); + m_timer[idx]->adjust(attotime::never); } m_gate[idx] = state; } @@ -675,14 +778,28 @@ void ptm6840_device::set_gate(int idx, int state) void ptm6840_device::set_clock(int idx, int state) { + if (m_clk[idx] == state) + { + return; + } + + const bool old_clk = m_clk[idx]; m_clk[idx] = state; + const bool rising_edge = !old_clk && state; + if (rising_edge) + { + return; + } - if (!(m_control_reg[idx] & INTERNAL_CLK_EN)) + const bool use_external_clk = !(m_control_reg[idx] & INTERNAL_CLK_EN); + const bool timer_running = !(m_control_reg[0] & RESET_TIMERS); + const bool one_shot_mode = m_mode[idx] == 4 || m_mode[idx] == 6; + const bool gated = !one_shot_mode && m_gate[idx]; + + // Don't allow ticking if timers are held in reset, internally-clocked, or gated + if (use_external_clk && timer_running && !gated) { - if (state) - { - tick(idx, 1); - } + tick(idx, 1); } } @@ -691,44 +808,52 @@ void ptm6840_device::set_clock(int idx, int state) // set_ext_clock - set external clock frequency //------------------------------------------------- -void ptm6840_device::set_ext_clock(int counter, double clock) +void ptm6840_device::set_ext_clock(int idx, double clk) { - m_external_clock[counter] = clock; + if (m_external_clock[idx] == clk) + return; - if (!(m_control_reg[counter] & INTERNAL_CLK_EN)) + m_counter[idx] = compute_counter(idx); + if (!(m_control_reg[idx] & INTERNAL_CLK_EN) && clk == 0.0) { - if (!m_external_clock[counter]) - { - m_enabled[counter] = 0; - m_timer[counter]->enable(false); - } + m_enabled[idx] = 0; + m_timer[idx]->adjust(attotime::never); } else { - int count; - attotime duration; + double new_clk = (m_control_reg[idx] & INTERNAL_CLK_EN) ? (double)clock() : clk; // Determine the number of clock periods before we expire - count = m_counter[counter]; + int count = m_counter[idx]; - if (m_control_reg[counter] & COUNT_MODE_8BIT) + if (m_control_reg[idx] & COUNT_MODE_8BIT) { count = ((count >> 8) + 1) * ((count & 0xff) + 1); } - else - { - count = count + 1; - } - duration = attotime::from_hz(clock) * count; + attotime duration = attotime::from_hz(new_clk) * count; - if (counter == 2) + if (idx == 2) { duration *= m_t3_divisor; } - m_enabled[counter] = 1; - m_timer[counter]->adjust(duration, counter); - m_timer[counter]->enable(true); + duration += attotime::from_ticks(2, clock()); + + m_enabled[idx] = 1; + + const bool one_shot_mode = m_mode[idx] == 4 || m_mode[idx] == 6; + const bool gated = (!one_shot_mode && m_gate[idx]) || (m_control_reg[0] & RESET_TIMERS); + if (gated) + { + m_disable_time[idx] = duration; + m_timer[idx]->adjust(attotime::never); + } + else + { + m_timer[idx]->adjust(duration, idx); + } } + + m_external_clock[idx] = clk; } diff --git a/src/devices/machine/6840ptm.h b/src/devices/machine/6840ptm.h index 99da9522c7b..9cab9cbd1ba 100644 --- a/src/devices/machine/6840ptm.h +++ b/src/devices/machine/6840ptm.h @@ -88,6 +88,7 @@ private: T3_PRESCALE_EN = 0x01, INTERNAL_CLK_EN = 0x02, COUNT_MODE_8BIT = 0x04, + MODE_BITS = 0x38, INTERRUPT_EN = 0x40, COUNT_OUT_EN = 0x80 }; @@ -106,12 +107,12 @@ private: devcb_write_line m_irq_cb; uint8_t m_control_reg[3]; - uint8_t m_output[3]; // Output states - uint8_t m_gate[3]; // Input gate states - uint8_t m_clk[3]; // Clock states - uint8_t m_enabled[3]; + bool m_output[3]; // Output states + bool m_gate[3]; // Counter gate states + bool m_clk[3]; // Clock states + bool m_enabled[3]; uint8_t m_mode[3]; - uint8_t m_fired[3]; + bool m_fired[3]; uint8_t m_t3_divisor; uint8_t m_t3_scaler; uint8_t m_irq; @@ -125,6 +126,7 @@ private: uint16_t m_latch[3]; uint16_t m_counter[3]; + attotime m_disable_time[3]; static const char *const opmode[]; diff --git a/src/mame/fairlight/cmi.cpp b/src/mame/fairlight/cmi.cpp index 23d8873e332..c08aa4e0bcc 100644 --- a/src/mame/fairlight/cmi.cpp +++ b/src/mame/fairlight/cmi.cpp @@ -104,6 +104,8 @@ #include "screen.h" #include "speaker.h" +#define LOG_CHANNELS (1 << 1U) + #define VERBOSE (0) #include "logmacro.h" @@ -219,8 +221,7 @@ public: , m_lp_y_port(*this, "LP_Y") , m_lp_touch_port(*this, "LP_TOUCH") , m_cmi07_ram(*this, "cmi07_ram") - , m_cpu1_periphs(*this, "cpu1_periphs") - , m_cpu2_periphs(*this, "cpu2_periphs") + , m_cpu_periphs(*this, "cpu%u_periphs", 1U) { } @@ -244,8 +245,8 @@ public: DECLARE_WRITE_LINE_MEMBER( i8214_3_enlg ); uint8_t shared_ram_r(offs_t offset); void shared_ram_w(offs_t offset, uint8_t data); - template uint8_t perr_r(offs_t offset); - template void perr_w(offs_t offset, uint8_t data); + template uint8_t perr_r(offs_t offset); + template void perr_w(offs_t offset, uint8_t data); uint16_t m_aic_ad565_in[16]{}; uint8_t m_aic_mux_latch = 0; @@ -275,14 +276,14 @@ public: uint8_t vram_r(offs_t offset); void vram_w(offs_t offset, uint8_t data); - template uint8_t ram_range_r(offs_t offset); - template void ram_range_w(offs_t offset, uint8_t data); - template uint8_t vram_range_r(offs_t offset); - template void vram_range_w(offs_t offset, uint8_t data); - template uint8_t cards_range_r(offs_t offset); - template void cards_range_w(offs_t offset, uint8_t data); - template uint8_t periphs_range_r(offs_t offset); - template void periphs_range_w(offs_t offset, uint8_t data); + template uint8_t ram_range_r(offs_t offset); + template void ram_range_w(offs_t offset, uint8_t data); + template uint8_t vram_range_r(offs_t offset); + template void vram_range_w(offs_t offset, uint8_t data); + template uint8_t cards_range_r(offs_t offset); + template void cards_range_w(offs_t offset, uint8_t data); + template uint8_t periphs_range_r(offs_t offset); + template void periphs_range_w(offs_t offset, uint8_t data); uint8_t tvt_r(); void tvt_w(uint8_t data); @@ -292,21 +293,21 @@ public: uint32_t screen_update_cmi2x(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); // Memory mapping - template uint8_t rom_r(offs_t offset); + template uint8_t rom_r(offs_t offset); void map_ram_w(offs_t offset, uint8_t data); - template uint8_t vector_r(offs_t offset); - template uint8_t map_r(); - template void map_w(uint8_t data); + template uint8_t vector_r(offs_t offset); + template uint8_t map_r(); + template void map_w(uint8_t data); uint8_t atomic_r(); void cpufunc_w(uint8_t data); uint8_t parity_r(offs_t offset); void mapsel_w(offs_t offset, uint8_t data); - template uint8_t irq_ram_r(offs_t offset); - template void irq_ram_w(offs_t offset, uint8_t data); - template uint8_t scratch_ram_r(offs_t offset); - template void scratch_ram_w(offs_t offset, uint8_t data); - template uint8_t scratch_ram_fa_r(offs_t offset); - template void scratch_ram_fa_w(offs_t offset, uint8_t data); + template uint8_t irq_ram_r(offs_t offset); + template void irq_ram_w(offs_t offset, uint8_t data); + template uint8_t scratch_ram_r(offs_t offset); + template void scratch_ram_w(offs_t offset, uint8_t data); + template uint8_t scratch_ram_fa_r(offs_t offset); + template void scratch_ram_fa_w(offs_t offset, uint8_t data); // MIDI/SMPTE void midi_dma_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); @@ -326,7 +327,9 @@ public: uint8_t cmi02_r(offs_t offset); void cmi02_w(offs_t offset, uint8_t data); void cmi02_chsel_w(uint8_t data); + uint8_t cmi02_chsel_r(); void master_tune_w(uint8_t data); + uint8_t master_tune_r(); DECLARE_WRITE_LINE_MEMBER( cmi02_ptm_irq ); DECLARE_WRITE_LINE_MEMBER( cmi02_ptm_o2 ); DECLARE_WRITE_LINE_MEMBER( cmi02_pia2_irqa_w ); @@ -347,8 +350,7 @@ public: void maincpu2_map(address_map &map); void midicpu_map(address_map &map); - void cpu1_periphs_map(address_map &map); - void cpu2_periphs_map(address_map &map); + template void cpu_periphs_map(address_map &map); protected: required_device m_maincpu1; @@ -394,8 +396,7 @@ protected: required_shared_ptr m_cmi07_ram; - required_device m_cpu1_periphs; - required_device m_cpu2_periphs; + required_device_array m_cpu_periphs; address_space *m_cpu1space = nullptr; address_space *m_cpu2space = nullptr; @@ -469,6 +470,7 @@ private: // Master card (CMI-02) int m_cmi02_ptm_irq = 0; uint8_t m_cmi02_pia_chsel = 0; + uint8_t m_master_tune = 0; }; /************************************** @@ -684,47 +686,47 @@ uint8_t cmi_state::vram_r(offs_t offset) /* Memory handling */ -template uint8_t cmi_state::rom_r(offs_t offset) +template uint8_t cmi_state::rom_r(offs_t offset) { - uint16_t base = (cpunum ? 0x1000 : 0x2000); + uint16_t base = (CpuNum ? 0x1000 : 0x2000); return *(((uint8_t *)m_q133_region->base()) + base + offset); } -template uint8_t cmi_state::perr_r(offs_t offset) +template uint8_t cmi_state::perr_r(offs_t offset) { m_maincpu2_irq0_merger->in_w<1>(1); const uint8_t page = offset >> 11; - const uint8_t mapinfo = m_curr_mapinfo[cpunum]; + const uint8_t mapinfo = m_curr_mapinfo[CpuNum]; const uint8_t page_info = m_map_ram[0][((mapinfo & 0x1f) << PAGE_SHIFT) + page]; const uint8_t data = m_q256_ram[0][(page_info & 0x7f) * PAGE_SIZE + (offset & 0x7ff)]; return data; } -template void cmi_state::perr_w(offs_t offset, uint8_t data) +template void cmi_state::perr_w(offs_t offset, uint8_t data) { const uint8_t page = offset >> 11; - const uint8_t mapinfo = m_curr_mapinfo[cpunum]; + const uint8_t mapinfo = m_curr_mapinfo[CpuNum]; const uint8_t page_info = m_map_ram[0][((mapinfo & 0x1f) << PAGE_SHIFT) + page]; m_q256_ram[0][(page_info & 0x7f) * PAGE_SIZE + (offset & 0x7ff)] = data; } -template uint8_t cmi_state::ram_range_r(offs_t offset) +template uint8_t cmi_state::ram_range_r(offs_t offset) { const uint16_t addr = base + offset; - const uint8_t mapinfo = m_curr_mapinfo[cpunum]; + const uint8_t mapinfo = m_curr_mapinfo[CpuNum]; const bool perr_en = BIT(mapinfo, 6); const uint8_t page = addr >> 11; const uint8_t page_info = m_map_ram[0][((mapinfo & 0x1f) << PAGE_SHIFT) + page]; - if (m_cmi07_base_enable[cpunum] && (addr & 0xc000) == m_cmi07_base_addr) + if (m_cmi07_base_enable[CpuNum] && (addr & 0xc000) == m_cmi07_base_addr) { return m_cmi07_ram[(page * PAGE_SIZE) & 0x3fff]; } if (perr_en) { - return perr_r(addr); + return perr_r(addr); } else if (BIT(page_info, 7)) { @@ -735,15 +737,15 @@ template uint8_t cmi_state::ram_range_r(offs_t offse return 0x00; } -template void cmi_state::ram_range_w(offs_t offset, uint8_t data) +template void cmi_state::ram_range_w(offs_t offset, uint8_t data) { const uint16_t addr = base + offset; - const uint8_t mapinfo = m_curr_mapinfo[cpunum]; + const uint8_t mapinfo = m_curr_mapinfo[CpuNum]; const bool perr_en = BIT(mapinfo, 6); const uint8_t page = addr >> 11; const uint8_t page_info = m_map_ram[0][((mapinfo & 0x1f) << PAGE_SHIFT) + page]; - if (m_cmi07_base_enable[cpunum] && (addr & 0xc000) == m_cmi07_base_addr) + if (m_cmi07_base_enable[CpuNum] && (addr & 0xc000) == m_cmi07_base_addr) { m_cmi07_ram[(page * PAGE_SIZE) & 0x3fff] = data; return; @@ -751,7 +753,7 @@ template void cmi_state::ram_range_w(offs_t offset, if (perr_en) { - perr_w(addr, data); + perr_w(addr, data); } else if (BIT(page_info, 7)) { @@ -760,9 +762,9 @@ template void cmi_state::ram_range_w(offs_t offset, } } -template uint8_t cmi_state::vram_range_r(offs_t offset) +template uint8_t cmi_state::vram_range_r(offs_t offset) { - const uint8_t mapinfo = m_curr_mapinfo[cpunum]; + const uint8_t mapinfo = m_curr_mapinfo[CpuNum]; if (!BIT(mapinfo, 5)) { return vram_r(offset); @@ -773,7 +775,7 @@ template uint8_t cmi_state::vram_range_r(offs_t offset) const uint8_t page = (offset >> 11) + 16; const uint8_t page_info = m_map_ram[0][((mapinfo & 0x1f) << PAGE_SHIFT) + page]; - if (m_cmi07_base_enable[cpunum] && (address & 0xc000) == m_cmi07_base_addr) + if (m_cmi07_base_enable[CpuNum] && (address & 0xc000) == m_cmi07_base_addr) { return m_cmi07_ram[(page * PAGE_SIZE) & 0x3fff]; } @@ -788,9 +790,9 @@ template uint8_t cmi_state::vram_range_r(offs_t offset) return 0x00; } -template void cmi_state::vram_range_w(offs_t offset, uint8_t data) +template void cmi_state::vram_range_w(offs_t offset, uint8_t data) { - const uint8_t mapinfo = m_curr_mapinfo[cpunum]; + const uint8_t mapinfo = m_curr_mapinfo[CpuNum]; if (!BIT(mapinfo, 5)) { vram_w(offset, data); @@ -801,7 +803,7 @@ template void cmi_state::vram_range_w(offs_t offset, uint8_t data) const uint8_t page = (offset >> 11) + 16; const uint8_t page_info = m_map_ram[0][((mapinfo & 0x1f) << PAGE_SHIFT) + page]; - if (m_cmi07_base_enable[cpunum] && (address & 0xc000) == m_cmi07_base_addr) + if (m_cmi07_base_enable[CpuNum] && (address & 0xc000) == m_cmi07_base_addr) { m_cmi07_ram[(page * PAGE_SIZE) & 0x3fff] = data; return; @@ -815,9 +817,9 @@ template void cmi_state::vram_range_w(offs_t offset, uint8_t data) } } -template uint8_t cmi_state::cards_range_r(offs_t offset) +template uint8_t cmi_state::cards_range_r(offs_t offset) { - const uint8_t mapinfo = m_curr_mapinfo[cpunum]; + const uint8_t mapinfo = m_curr_mapinfo[CpuNum]; if (!BIT(mapinfo, 7) && offset < 0x40) { return cmi02_r(offset); @@ -836,9 +838,9 @@ template uint8_t cmi_state::cards_range_r(offs_t offset) return 0x00; } -template void cmi_state::cards_range_w(offs_t offset, uint8_t data) +template void cmi_state::cards_range_w(offs_t offset, uint8_t data) { - const uint8_t mapinfo = m_curr_mapinfo[cpunum]; + const uint8_t mapinfo = m_curr_mapinfo[CpuNum]; if (!BIT(mapinfo, 7) && offset < 0x40) { cmi02_w(offset, data); @@ -856,15 +858,12 @@ template void cmi_state::cards_range_w(offs_t offset, uint8_t data) } } -template uint8_t cmi_state::periphs_range_r(offs_t offset) +template uint8_t cmi_state::periphs_range_r(offs_t offset) { - const uint8_t mapinfo = m_curr_mapinfo[cpunum]; + const uint8_t mapinfo = m_curr_mapinfo[CpuNum]; if (!BIT(mapinfo, 7)) { - if (cpunum) - return m_cpu2_periphs->read8(offset); - else - return m_cpu1_periphs->read8(offset); + return m_cpu_periphs[CpuNum]->read8(offset); } else { @@ -881,15 +880,12 @@ template uint8_t cmi_state::periphs_range_r(offs_t offset) return 0x00; } -template void cmi_state::periphs_range_w(offs_t offset, uint8_t data) +template void cmi_state::periphs_range_w(offs_t offset, uint8_t data) { - const uint8_t mapinfo = m_curr_mapinfo[cpunum]; + const uint8_t mapinfo = m_curr_mapinfo[CpuNum]; if (!BIT(mapinfo, 7)) { - if (cpunum) - m_cpu2_periphs->write8(offset, data); - else - m_cpu1_periphs->write8(offset, data); + m_cpu_periphs[CpuNum]->write8(offset, data); } else { @@ -927,38 +923,38 @@ void cmi_state::map_ram_w(offs_t offset, uint8_t data) } } -template uint8_t cmi_state::vector_r(offs_t offset) +template uint8_t cmi_state::vector_r(offs_t offset) { - return m_q133_rom[(cpunum ? 0xbfe : 0xffe) + offset]; + return m_q133_rom[(CpuNum ? 0xbfe : 0xffe) + offset]; } -template uint8_t cmi_state::map_r() +template uint8_t cmi_state::map_r() { - return (m_cpu_active_space[1] << 2) | (m_cpu_active_space[0] << 1) | cpunum; + return (m_cpu_active_space[1] << 2) | (m_cpu_active_space[0] << 1) | CpuNum; } -template void cmi_state::map_w(uint8_t data) +template void cmi_state::map_w(uint8_t data) { - m_map_switch_timer->adjust(attotime::from_ticks(data & 0xf, M6809_CLOCK), cpunum); + m_map_switch_timer->adjust(attotime::from_ticks(data & 0xf, M6809_CLOCK), CpuNum); } -template uint8_t cmi_state::irq_ram_r(offs_t offset) +template uint8_t cmi_state::irq_ram_r(offs_t offset) { if (machine().side_effects_disabled()) - return m_scratch_ram[cpunum][0xf8 + offset]; + return m_scratch_ram[CpuNum][0xf8 + offset]; - if (m_m6809_bs_hack_cnt[cpunum] > 0) + 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, 1 - m_m6809_bs_hack_cnt[cpunum], offset, m_irq_address[cpunum][offset]); - return m_irq_address[cpunum][offset]; + m_m6809_bs_hack_cnt[CpuNum]--; + 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]; + return m_scratch_ram[CpuNum][0xf8 + offset]; } -template void cmi_state::irq_ram_w(offs_t offset, uint8_t data) +template void cmi_state::irq_ram_w(offs_t offset, uint8_t data) { - m_scratch_ram[cpunum][0xf8 + offset] = data; + m_scratch_ram[CpuNum][0xf8 + offset] = data; } TIMER_CALLBACK_MEMBER(cmi_state::switch_map) @@ -1154,14 +1150,15 @@ void cmi_state::cmi07cpu_map(address_map &map) map(0xc000, 0xffff).ram().share("cmi07_ram"); } -void cmi_state::cpu1_periphs_map(address_map &map) +template void cmi_state::cpu_periphs_map(address_map &map) { - map(0x0000, 0x07ff).rw(FUNC(cmi_state::rom_r<0>), FUNC(cmi_state::map_ram_w)); - map(0x0800, 0x0bff).rom().region("q133", 0x2800); + map.unmap_value_high(); + map(0x0000, 0x07ff).rw(FUNC(cmi_state::rom_r), FUNC(cmi_state::map_ram_w)); + map(0x0800, 0x0bff).rom().region("q133", 0x2800 - CpuNum * 0x1000); map(0x0c40, 0x0c4f).rw(FUNC(cmi_state::parity_r), FUNC(cmi_state::mapsel_w)); map(0x0c5a, 0x0c5b).noprw(); // Q077 HDD controller - not installed map(0x0c5e, 0x0c5e).rw(FUNC(cmi_state::atomic_r), FUNC(cmi_state::cpufunc_w)); - map(0x0c5f, 0x0c5f).rw(FUNC(cmi_state::map_r<0>), FUNC(cmi_state::map_w<0>)); + map(0x0c5f, 0x0c5f).rw(FUNC(cmi_state::map_r), FUNC(cmi_state::map_w)); map(0x0c80, 0x0c83).rw(m_q133_acia[0], FUNC(mos6551_device::read), FUNC(mos6551_device::write)); map(0x0c84, 0x0c87).rw(m_q133_acia[1], FUNC(mos6551_device::read), FUNC(mos6551_device::write)); map(0x0c88, 0x0c8b).rw(m_q133_acia[2], FUNC(mos6551_device::read), FUNC(mos6551_device::write)); @@ -1180,41 +1177,10 @@ void cmi_state::cpu1_periphs_map(address_map &map) map(0x0cfc, 0x0cfc).w(FUNC(cmi_state::i8214_cpu1_w)); map(0x0cfd, 0x0cfd).w(FUNC(cmi_state::i8214_cpu2_w)); map(0x0d00, 0x0eff).rw(FUNC(cmi_state::shared_ram_r), FUNC(cmi_state::shared_ram_w)); - map(0x0f00, 0x0ff7).rw(FUNC(cmi_state::scratch_ram_r<0>), FUNC(cmi_state::scratch_ram_w<0>)); - map(0x0ff8, 0x0ff9).rw(FUNC(cmi_state::irq_ram_r<0>), FUNC(cmi_state::irq_ram_w<0>)); - map(0x0ffa, 0x0ffd).rw(FUNC(cmi_state::scratch_ram_fa_r<0>), FUNC(cmi_state::scratch_ram_fa_w<0>)); - map(0x0ffe, 0x0fff).r(FUNC(cmi_state::vector_r<0>)); -} - -void cmi_state::cpu2_periphs_map(address_map &map) -{ - map(0x0000, 0x07ff).rw(FUNC(cmi_state::rom_r<1>), FUNC(cmi_state::map_ram_w)); - map(0x0800, 0x0bff).rom().region("q133", 0x1800); - map(0x0c40, 0x0c4f).rw(FUNC(cmi_state::parity_r), FUNC(cmi_state::mapsel_w)); - map(0x0c5a, 0x0c5b).noprw(); // Q077 HDD controller - not installed - map(0x0c5e, 0x0c5e).rw(FUNC(cmi_state::atomic_r), FUNC(cmi_state::cpufunc_w)); - map(0x0c5f, 0x0c5f).rw(FUNC(cmi_state::map_r<1>), FUNC(cmi_state::map_w<1>)); - map(0x0c80, 0x0c83).rw(m_q133_acia[0], FUNC(mos6551_device::read), FUNC(mos6551_device::write)); - map(0x0c84, 0x0c87).rw(m_q133_acia[1], FUNC(mos6551_device::read), FUNC(mos6551_device::write)); - map(0x0c88, 0x0c8b).rw(m_q133_acia[2], FUNC(mos6551_device::read), FUNC(mos6551_device::write)); - map(0x0c8c, 0x0c8f).rw(m_q133_acia[3], FUNC(mos6551_device::read), FUNC(mos6551_device::write)); - map(0x0c90, 0x0c97).rw(m_q133_ptm, FUNC(ptm6840_device::read), FUNC(ptm6840_device::write)); - //map(0x0ca0, 0x0ca0).w(FUNC(cmi_state::midi_latch_w)); - map(0x0cc0, 0x0cc3).r(FUNC(cmi_state::lightpen_r)); - map(0x0cc4, 0x0cc7).rw(m_q219_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); - map(0x0cc8, 0x0ccf).rw(m_q219_ptm, FUNC(ptm6840_device::read), FUNC(ptm6840_device::write)); - map(0x0cd0, 0x0cdc).rw(FUNC(cmi_state::video_r), FUNC(cmi_state::video_w)); - map(0x0ce0, 0x0ce1).rw(FUNC(cmi_state::fdc_r), FUNC(cmi_state::fdc_w)); - map(0x0ce2, 0x0cef).noprw(); // Monitor ROM will attempt to detect floppy disk controller cards in this entire range - map(0x0cf0, 0x0cf7).rw(m_q133_pia[0], FUNC(pia6821_device::read), FUNC(pia6821_device::write)); - map(0x0cf8, 0x0cff).rw(m_q133_pia[1], FUNC(pia6821_device::read), FUNC(pia6821_device::write)); - map(0x0cfc, 0x0cfc).w(FUNC(cmi_state::i8214_cpu1_w)); - map(0x0cfd, 0x0cfd).w(FUNC(cmi_state::i8214_cpu2_w)); - map(0x0d00, 0x0eff).rw(FUNC(cmi_state::shared_ram_r), FUNC(cmi_state::shared_ram_w)); - map(0x0f00, 0x0ff7).rw(FUNC(cmi_state::scratch_ram_r<1>), FUNC(cmi_state::scratch_ram_w<1>)); - map(0x0ff8, 0x0ff9).rw(FUNC(cmi_state::irq_ram_r<1>), FUNC(cmi_state::irq_ram_w<1>)); - map(0x0ffa, 0x0ffd).rw(FUNC(cmi_state::scratch_ram_fa_r<1>), FUNC(cmi_state::scratch_ram_fa_w<1>)); - map(0x0ffe, 0x0fff).r(FUNC(cmi_state::vector_r<1>)); + map(0x0f00, 0x0ff7).rw(FUNC(cmi_state::scratch_ram_r), FUNC(cmi_state::scratch_ram_w)); + map(0x0ff8, 0x0ff9).rw(FUNC(cmi_state::irq_ram_r), FUNC(cmi_state::irq_ram_w)); + map(0x0ffa, 0x0ffd).rw(FUNC(cmi_state::scratch_ram_fa_r), FUNC(cmi_state::scratch_ram_fa_w)); + map(0x0ffe, 0x0fff).r(FUNC(cmi_state::vector_r)); } /* Input ports */ @@ -1229,24 +1195,24 @@ static INPUT_PORTS_START( cmi2x ) PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME ( "Lightpen Touch" ) PORT_CODE( MOUSECODE_BUTTON1 ) INPUT_PORTS_END -template uint8_t cmi_state::scratch_ram_r(offs_t offset) +template uint8_t cmi_state::scratch_ram_r(offs_t offset) { - return m_scratch_ram[cpunum][offset]; + return m_scratch_ram[CpuNum][offset]; } -template void cmi_state::scratch_ram_w(offs_t offset, uint8_t data) +template void cmi_state::scratch_ram_w(offs_t offset, uint8_t data) { - m_scratch_ram[cpunum][offset] = data; + m_scratch_ram[CpuNum][offset] = data; } -template uint8_t cmi_state::scratch_ram_fa_r(offs_t offset) +template uint8_t cmi_state::scratch_ram_fa_r(offs_t offset) { - return m_scratch_ram[cpunum][0xfa + offset]; + return m_scratch_ram[CpuNum][0xfa + offset]; } -template void cmi_state::scratch_ram_fa_w(offs_t offset, uint8_t data) +template void cmi_state::scratch_ram_fa_w(offs_t offset, uint8_t data) { - m_scratch_ram[cpunum][0xfa + offset] = data; + m_scratch_ram[CpuNum][0xfa + offset] = data; } bool cmi_state::map_is_active(int cpunum, int map, uint8_t *map_info) @@ -1542,7 +1508,17 @@ WRITE_LINE_MEMBER( cmi_state::wd1791_drq ) void cmi_state::master_tune_w(uint8_t data) { -// double mfreq = (double)data * ((double)MASTER_OSCILLATOR / 2.0) / 256.0; + m_master_tune = data; + double mfreq = ((0xf00 | data) * (MASTER_OSCILLATOR.dvalue() / 2.0)) / 4096.0; + for (int i = 0; i < 8; i++) + { + m_channels[i]->set_master_osc(mfreq); + } +} + +uint8_t cmi_state::master_tune_r() +{ + return m_master_tune; } void cmi_state::cmi02_chsel_w(uint8_t data) @@ -1550,9 +1526,13 @@ void cmi_state::cmi02_chsel_w(uint8_t data) m_cmi02_pia_chsel = data; } +uint8_t cmi_state::cmi02_chsel_r() +{ + return m_cmi02_pia_chsel; +} + WRITE_LINE_MEMBER( cmi_state::cmi02_ptm_irq ) { - LOG("%s: cmi02_ptm_irq: %d\n", machine().describe_context(), state); m_cmi02_ptm_irq = state; set_interrupt(CPU_1, IRQ_TIMINT_LEVEL, m_cmi02_ptm_irq ? ASSERT_LINE : CLEAR_LINE); } @@ -1583,13 +1563,11 @@ uint8_t cmi_state::cmi02_r(offs_t offset) if (offset <= 0x1f) { - int ch_mask = m_cmi02_pia_chsel; - - for (int i = 0; i < 8; ++i) + for (int i = 0; i < 8; i++) { - if (ch_mask & (1 << i)) + if (BIT(m_cmi02_pia_chsel, i)) { - return m_channels[i]->read(offset & 0x1f); + return m_channels[i]->read(offset); } } @@ -1597,39 +1575,29 @@ uint8_t cmi_state::cmi02_r(offs_t offset) } else { - uint8_t data = 0; switch (offset) { case 0x20: case 0x21: case 0x22: case 0x23: - 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; + return m_cmi02_pia[0]->read(offset & 3); 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: - 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; + return m_cmi02_pia[1]->read(offset & 3); case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: - data = m_cmi02_ptm->read(offset & 7); - LOG("%s: CMI02 PTM read (offset %d): %02x\n", machine().describe_context(), offset & 7, data); - return data; + return m_cmi02_ptm->read(offset & 7); default: - LOG("%s: CMI02 Unknown read (offset %02x): %02x\n", machine().describe_context(), offset, 0x00); - return data; + return 0; } } } @@ -1638,12 +1606,12 @@ void cmi_state::cmi02_w(offs_t offset, uint8_t data) { if (offset <= 0x1f) { - int ch_mask = m_cmi02_pia_chsel; - - for (int i = 0; i < 8; ++i) + for (int i = 0; i < 8; i++) { - if (ch_mask & (1 << i)) + if (BIT(m_cmi02_pia_chsel, i)) + { m_channels[i]->write(offset & 0x1f, data); + } } } else @@ -1651,41 +1619,32 @@ void cmi_state::cmi02_w(offs_t offset, uint8_t 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: - 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; } } @@ -1694,16 +1653,17 @@ void cmi_state::cmi02_w(offs_t offset, uint8_t data) template WRITE_LINE_MEMBER(cmi_state::channel_irq) { + if (Channel == 0) + { + LOGMASKED(LOG_CHANNELS, "Channel IRQ: %d\n", state); + } set_interrupt(CPU_1, ch_int_levels[Channel], state); } 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); 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)); } @@ -2106,22 +2066,21 @@ void cmi_state::cmi2x(machine_config &config) MC6809E(config, m_maincpu1, Q209_CPU_CLOCK); m_maincpu1->set_addrmap(AS_PROGRAM, &cmi_state::maincpu1_map); m_maincpu1->set_irq_acknowledge_callback(FUNC(cmi_state::cpu1_interrupt_callback)); - config.set_perfect_quantum(m_maincpu1); MC6809E(config, m_maincpu2, Q209_CPU_CLOCK); m_maincpu2->set_addrmap(AS_PROGRAM, &cmi_state::maincpu2_map); m_maincpu2->set_irq_acknowledge_callback(FUNC(cmi_state::cpu2_interrupt_callback)); - ADDRESS_MAP_BANK(config, m_cpu1_periphs).set_options(ENDIANNESS_BIG, 8, 16, 0x1000); - m_cpu1_periphs->set_addrmap(AS_PROGRAM, &cmi_state::cpu1_periphs_map); + ADDRESS_MAP_BANK(config, m_cpu_periphs[0]).set_options(ENDIANNESS_BIG, 8, 16, 0x1000); + m_cpu_periphs[0]->set_addrmap(AS_PROGRAM, &cmi_state::cpu_periphs_map<0>); - ADDRESS_MAP_BANK(config, m_cpu2_periphs).set_options(ENDIANNESS_BIG, 8, 16, 0x1000); - m_cpu2_periphs->set_addrmap(AS_PROGRAM, &cmi_state::cpu2_periphs_map); + ADDRESS_MAP_BANK(config, m_cpu_periphs[1]).set_options(ENDIANNESS_BIG, 8, 16, 0x1000); + m_cpu_periphs[1]->set_addrmap(AS_PROGRAM, &cmi_state::cpu_periphs_map<1>); M68000(config, m_midicpu, 20_MHz_XTAL / 2); m_midicpu->set_addrmap(AS_PROGRAM, &cmi_state::midicpu_map); - MC6809E(config, m_cmi07cpu, Q209_CPU_CLOCK); // ? + MC6809E(config, m_cmi07cpu, Q209_CPU_CLOCK); m_cmi07cpu->set_addrmap(AS_PROGRAM, &cmi_state::cmi07cpu_map); /* video hardware */ @@ -2134,18 +2093,18 @@ void cmi_state::cmi2x(machine_config &config) MSM5832(config, m_msm5832, 32.768_kHz_XTAL); - I8214(config, m_i8214[0], 1000000); // cmi_8214_intf_1 + I8214(config, m_i8214[0], 1000000); m_i8214[0]->int_wr_callback().set(FUNC(cmi_state::i8214_1_int_w)); - I8214(config, m_i8214[1], 1000000); // cmi_8214_intf_2 + I8214(config, m_i8214[1], 1000000); m_i8214[1]->int_wr_callback().set(FUNC(cmi_state::i8214_2_int_w)); - I8214(config, m_i8214[2], 1000000); // cmi_8214_intf_3 + I8214(config, m_i8214[2], 1000000); m_i8214[2]->int_wr_callback().set(FUNC(cmi_state::i8214_3_int_w)); m_i8214[2]->enlg_wr_callback().set(FUNC(cmi_state::i8214_3_enlg)); INPUT_MERGER_ANY_HIGH(config, m_maincpu1_irq_merger).output_handler().set(FUNC(cmi_state::maincpu1_irq_w)); INPUT_MERGER_ANY_HIGH(config, m_maincpu2_irq0_merger).output_handler().set(FUNC(cmi_state::maincpu2_irq0_w)); - PIA6821(config, m_q133_pia[0]); // pia_q133_1_config + PIA6821(config, m_q133_pia[0]); m_q133_pia[0]->readpa_handler().set(FUNC(cmi_state::q133_1_porta_r)); m_q133_pia[0]->writepa_handler().set(FUNC(cmi_state::q133_1_porta_w)); m_q133_pia[0]->writepb_handler().set(FUNC(cmi_state::q133_1_portb_w)); @@ -2154,28 +2113,30 @@ void cmi_state::cmi2x(machine_config &config) INPUT_MERGER_ANY_HIGH(config, "rtc_irq_merger").output_handler().set(FUNC(cmi_state::msm5832_irq_w)); - PIA6821(config, m_q133_pia[1]); // pia_q133_2_config + PIA6821(config, m_q133_pia[1]); - PTM6840(config, m_q133_ptm, SYSTEM_CAS_CLOCK); // ptm_q133_config, clock likely not accurate + PTM6840(config, m_q133_ptm, SYSTEM_CAS_CLOCK); m_q133_ptm->set_external_clocks(1024, 1, 111); // Third is todo m_q133_ptm->irq_callback().set(FUNC(cmi_state::q133_ptm_irq_w)); - PIA6821(config, m_q219_pia); // pia_q219_config + PIA6821(config, m_q219_pia); m_q219_pia->readpb_handler().set(FUNC(cmi_state::pia_q219_b_r)); m_q219_pia->writepa_handler().set(FUNC(cmi_state::vscroll_w)); m_q219_pia->writepb_handler().set(FUNC(cmi_state::video_attr_w)); m_q219_pia->irqa_handler().set(FUNC(cmi_state::pia_q219_irqa)); m_q219_pia->irqb_handler().set(FUNC(cmi_state::pia_q219_irqb)); - PTM6840(config, m_q219_ptm, SYSTEM_CAS_CLOCK); // ptm_q219_config + PTM6840(config, m_q219_ptm, SYSTEM_CAS_CLOCK); m_q219_ptm->set_external_clocks(HBLANK_FREQ.dvalue(), VBLANK_FREQ.dvalue(), SYSTEM_CAS_CLOCK.dvalue() / 2.0); m_q219_ptm->irq_callback().set(FUNC(cmi_state::ptm_q219_irq)); - PIA6821(config, m_cmi02_pia[0]); // pia_cmi02_1_config + PIA6821(config, m_cmi02_pia[0]); + m_cmi02_pia[0]->readpa_handler().set(FUNC(cmi_state::cmi02_chsel_r)); m_cmi02_pia[0]->writepa_handler().set(FUNC(cmi_state::cmi02_chsel_w)); + m_cmi02_pia[0]->readpb_handler().set(FUNC(cmi_state::master_tune_r)); m_cmi02_pia[0]->writepb_handler().set(FUNC(cmi_state::master_tune_w)); - PIA6821(config, m_cmi02_pia[1]); // pia_cmi02_2_config + PIA6821(config, m_cmi02_pia[1]); m_cmi02_pia[1]->irqa_handler().set(FUNC(cmi_state::cmi02_pia2_irqa_w)); m_cmi02_pia[1]->ca1_w(0); m_cmi02_pia[1]->cb2_handler().set(FUNC(cmi_state::cmi02_pia2_cb2_w)); @@ -2261,30 +2222,30 @@ void cmi_state::cmi2x(machine_config &config) SPEAKER(config, "mono").front_center(); // Channel cards - cmi01a_device &cmi01a_0(CMI01A_CHANNEL_CARD(config, "cmi01a_0", SYSTEM_CAS_CLOCK, 0)); - cmi01a_0.add_route(ALL_OUTPUTS, "mono", 0.12); - cmi01a_0.irq_callback().set(FUNC(cmi_state::channel_irq<0>)); - cmi01a_device &cmi01a_1(CMI01A_CHANNEL_CARD(config, "cmi01a_1", SYSTEM_CAS_CLOCK, 1)); - cmi01a_1.add_route(ALL_OUTPUTS, "mono", 0.12); - cmi01a_1.irq_callback().set(FUNC(cmi_state::channel_irq<1>)); - cmi01a_device &cmi01a_2(CMI01A_CHANNEL_CARD(config, "cmi01a_2", SYSTEM_CAS_CLOCK, 2)); - cmi01a_2.add_route(ALL_OUTPUTS, "mono", 0.12); - cmi01a_2.irq_callback().set(FUNC(cmi_state::channel_irq<2>)); - cmi01a_device &cmi01a_3(CMI01A_CHANNEL_CARD(config, "cmi01a_3", SYSTEM_CAS_CLOCK, 3)); - cmi01a_3.add_route(ALL_OUTPUTS, "mono", 0.12); - cmi01a_3.irq_callback().set(FUNC(cmi_state::channel_irq<3>)); - cmi01a_device &cmi01a_4(CMI01A_CHANNEL_CARD(config, "cmi01a_4", SYSTEM_CAS_CLOCK, 4)); - cmi01a_4.add_route(ALL_OUTPUTS, "mono", 0.12); - cmi01a_4.irq_callback().set(FUNC(cmi_state::channel_irq<4>)); - cmi01a_device &cmi01a_5(CMI01A_CHANNEL_CARD(config, "cmi01a_5", SYSTEM_CAS_CLOCK, 5)); - cmi01a_5.add_route(ALL_OUTPUTS, "mono", 0.12); - cmi01a_5.irq_callback().set(FUNC(cmi_state::channel_irq<5>)); - cmi01a_device &cmi01a_6(CMI01A_CHANNEL_CARD(config, "cmi01a_6", SYSTEM_CAS_CLOCK, 6)); - cmi01a_6.add_route(ALL_OUTPUTS, "mono", 0.12); - cmi01a_6.irq_callback().set(FUNC(cmi_state::channel_irq<6>)); - cmi01a_device &cmi01a_7(CMI01A_CHANNEL_CARD(config, "cmi01a_7", SYSTEM_CAS_CLOCK, 7)); - cmi01a_7.add_route(ALL_OUTPUTS, "mono", 0.12); - cmi01a_7.irq_callback().set(FUNC(cmi_state::channel_irq<7>)); + CMI01A_CHANNEL_CARD(config, m_channels[0], SYSTEM_CAS_CLOCK, 0); + m_channels[0]->add_route(ALL_OUTPUTS, "mono", 0.125); + m_channels[0]->irq_callback().set(FUNC(cmi_state::channel_irq<0>)); + CMI01A_CHANNEL_CARD(config, m_channels[1], SYSTEM_CAS_CLOCK, 1); + m_channels[1]->add_route(ALL_OUTPUTS, "mono", 0.125); + m_channels[1]->irq_callback().set(FUNC(cmi_state::channel_irq<1>)); + CMI01A_CHANNEL_CARD(config, m_channels[2], SYSTEM_CAS_CLOCK, 2); + m_channels[2]->add_route(ALL_OUTPUTS, "mono", 0.125); + m_channels[2]->irq_callback().set(FUNC(cmi_state::channel_irq<2>)); + CMI01A_CHANNEL_CARD(config, m_channels[3], SYSTEM_CAS_CLOCK, 3); + m_channels[3]->add_route(ALL_OUTPUTS, "mono", 0.125); + m_channels[3]->irq_callback().set(FUNC(cmi_state::channel_irq<3>)); + CMI01A_CHANNEL_CARD(config, m_channels[4], SYSTEM_CAS_CLOCK, 4); + m_channels[4]->add_route(ALL_OUTPUTS, "mono", 0.125); + m_channels[4]->irq_callback().set(FUNC(cmi_state::channel_irq<4>)); + CMI01A_CHANNEL_CARD(config, m_channels[5], SYSTEM_CAS_CLOCK, 5); + m_channels[5]->add_route(ALL_OUTPUTS, "mono", 0.125); + m_channels[5]->irq_callback().set(FUNC(cmi_state::channel_irq<5>)); + CMI01A_CHANNEL_CARD(config, m_channels[6], SYSTEM_CAS_CLOCK, 6); + m_channels[6]->add_route(ALL_OUTPUTS, "mono", 0.125); + m_channels[6]->irq_callback().set(FUNC(cmi_state::channel_irq<6>)); + CMI01A_CHANNEL_CARD(config, m_channels[7], SYSTEM_CAS_CLOCK, 7); + m_channels[7]->add_route(ALL_OUTPUTS, "mono", 0.125); + m_channels[7]->irq_callback().set(FUNC(cmi_state::channel_irq<7>)); } ROM_START( cmi2x ) diff --git a/src/mame/fairlight/cmi01a.cpp b/src/mame/fairlight/cmi01a.cpp index 105a535a2a9..767cf71b94f 100644 --- a/src/mame/fairlight/cmi01a.cpp +++ b/src/mame/fairlight/cmi01a.cpp @@ -12,172 +12,129 @@ #define VERBOSE (0) #include "logmacro.h" -#define MASTER_OSCILLATOR XTAL(34'291'712) - DEFINE_DEVICE_TYPE(CMI01A_CHANNEL_CARD, cmi01a_device, "cmi_01a", "Fairlight CMI-01A Channel Card") - -const uint8_t cmi01a_device::s_7497_rate_table[64][64] = -{ - {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, - {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, - {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, - {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, - {1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1}, - {1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1}, - {1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1}, - {1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1}, - {1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1}, - {1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1}, - {1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1}, - {1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1}, - {1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1}, - {1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1}, - {1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1}, - {1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1}, - {1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1}, - {1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1}, - {1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1}, - {1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1}, - {1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1}, - {1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1}, - {1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1}, - {1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1}, - {1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1}, - {1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1}, - {1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1}, - {1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1}, - {1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1}, - {1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1}, - {1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1}, - {1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1}, - {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}, - {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}, - {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}, - {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}, - {0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1}, - {0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1}, - {0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1}, - {0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1}, - {0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1}, - {0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1}, - {0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1}, - {0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1}, - {0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1}, - {0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1}, - {0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1}, - {0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1}, - {0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1}, - {0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1}, - {0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1}, - {0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1}, - {0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1}, - {0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1}, - {0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1}, - {0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1}, - {0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1}, - {0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1}, - {0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1}, - {0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1} -}; - -cmi01a_device::cmi01a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +cmi01a_device::cmi01a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 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) , m_stream(nullptr) + , m_zcint_pulse_timer(nullptr) + , m_rstb_pulse_timer(nullptr) + , m_bcas_q1_timer(nullptr) + , m_sample_timer(nullptr) , m_irq_cb(*this) + , m_current_sample(0), m_mosc(0.0), m_pitch(0), m_octave(0), m_zx_ff_clk(false), m_zx_ff(false), m_zx(false), m_gzx(false) + , m_run(false), m_not_rstb(true), m_not_load(false), m_not_zcint(true), m_not_wpe(true), m_new_addr(false) + , m_tri(false), m_permit_eload(false), m_not_eload(true), m_bcas_q1_enabled(true), m_bcas_q1(false), m_bcas_q2(false) + , m_env_dir(ENV_DIR_UP), m_env(0), m_env_divider(0), m_ediv_out(false), m_eclk(false), m_env_clk(false) + , m_wave_addr_lsb(0), m_wave_addr_msb(0), m_upper_wave_addr_load(false), m_wave_addr_msb_clock(true), m_run_load_xor(true), m_delayed_inverted_run_load(false) + , m_ptm_c1(false), m_ptm_o1(false), m_ptm_o2(false), m_ptm_o3(false) + , m_vol_latch(0), m_flt_latch(0), m_rp(0), m_ws(0), m_dir(ENV_DIR_UP) { } void cmi01a_device::device_add_mconfig(machine_config &config) { - PIA6821(config, m_pia[0], 0); // pia_cmi01a_1_config + PIA6821(config, m_pia[0], 0); // 6821 C6/7/8/9 m_pia[0]->readcb1_handler().set(FUNC(cmi01a_device::tri_r)); m_pia[0]->readpa_handler().set(FUNC(cmi01a_device::ws_dir_r)); m_pia[0]->writepa_handler().set(FUNC(cmi01a_device::ws_dir_w)); + m_pia[0]->readpb_handler().set(FUNC(cmi01a_device::rp_r)); m_pia[0]->writepb_handler().set(FUNC(cmi01a_device::rp_w)); - m_pia[0]->ca2_handler().set(FUNC(cmi01a_device::load_w)); - m_pia[0]->cb2_handler().set(FUNC(cmi01a_device::pia_0_cb2_w)); + m_pia[0]->ca2_handler().set(FUNC(cmi01a_device::notload_w)); + m_pia[0]->cb2_handler().set(FUNC(cmi01a_device::run_w)); 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>)); - //if (m_channel == 5) m_pia[0]->enable_logging(); - PIA6821(config, m_pia[1], 0); // pia_cmi01a_2_config + PIA6821(config, m_pia[1], 0); // 6821 D6/7/8/9 m_pia[1]->readca1_handler().set(FUNC(cmi01a_device::zx_r)); m_pia[1]->readcb1_handler().set(FUNC(cmi01a_device::eosi_r)); - m_pia[1]->readpa_handler().set(FUNC(cmi01a_device::pia_1_a_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]->ca2_handler().set(FUNC(cmi01a_device::eload_w)); - m_pia[1]->cb2_handler().set(FUNC(cmi01a_device::wpe_w)); + m_pia[1]->readpa_handler().set(FUNC(cmi01a_device::pitch_octave_r)); + m_pia[1]->writepa_handler().set(FUNC(cmi01a_device::pitch_octave_w)); + m_pia[1]->readpb_handler().set(FUNC(cmi01a_device::pitch_lsb_r)); + m_pia[1]->writepb_handler().set(FUNC(cmi01a_device::pitch_lsb_w)); + m_pia[1]->ca2_handler().set(FUNC(cmi01a_device::permit_eload_w)); + m_pia[1]->cb2_handler().set(FUNC(cmi01a_device::not_wpe_w)); 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>)); - //if (m_channel == 5) m_pia[1]->enable_logging(); - PTM6840(config, m_ptm, DERIVED_CLOCK(1, 1)); // ptm_cmi01a_config + PTM6840(config, m_ptm, DERIVED_CLOCK(1, 1)); m_ptm->o1_callback().set(FUNC(cmi01a_device::ptm_o1)); m_ptm->o2_callback().set(FUNC(cmi01a_device::ptm_o2)); m_ptm->o3_callback().set(FUNC(cmi01a_device::ptm_o3)); - m_ptm->irq_callback().set(FUNC(cmi01a_device::ptm_irq)); + m_ptm->irq_callback().set(m_irq_merger, FUNC(input_merger_device::in_w<4>)); 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, std::vector const &inputs, std::vector &outputs) +void cmi01a_device::device_start() { - if (m_run) - { - int mask = m_load ? 0x7fff : 0x7f; - int addr = m_segment_cnt; + m_wave_ram = std::make_unique(0x4000); - uint8_t *wave_ptr = &m_wave_ram[m_segment_cnt & 0x3fff]; - auto &buf = outputs[0]; + m_bcas_q1_timer = timer_alloc(FUNC(cmi01a_device::bcas_q1_tick), this); + m_zcint_pulse_timer = timer_alloc(FUNC(cmi01a_device::zcint_pulse_cb), this); + m_rstb_pulse_timer = timer_alloc(FUNC(cmi01a_device::rstb_pulse_cb), this); + m_sample_timer = timer_alloc(FUNC(cmi01a_device::update_sample), this); - for (int sampindex = 0; sampindex < buf.samples(); sampindex++) - { - const uint8_t sample8 = wave_ptr[addr++ & 0x3fff]; - s32 sample = (int32_t)(int8_t)(sample8 ^ 0x80) * m_env * m_vol_latch; -// if (m_channel == 5) printf("%08x:%02x:%02x:%02x", (uint32_t)sample, sample8, m_env, m_vol_latch); - buf.put_int(sampindex, (int16_t)(sample >> 8), 32768); - } -// if (m_channel == 5) printf("\n"); + m_stream = stream_alloc(0, 1, 48000); - m_segment_cnt = (m_segment_cnt & ~mask) | addr; - } - else - outputs[0].fill(0); -} + m_ptm->set_external_clocks(0, 0, 0); -void cmi01a_device::device_resolve_objects() -{ - m_irq_cb.resolve_safe(); -} + save_pointer(NAME(m_wave_ram), 0x4000); + save_item(NAME(m_current_sample)); -void cmi01a_device::device_start() -{ - m_wave_ram = std::make_unique(0x4000); + save_item(NAME(m_mosc)); + save_item(NAME(m_pitch)); + save_item(NAME(m_octave)); + + save_item(NAME(m_zx_ff_clk)); + save_item(NAME(m_zx_ff)); + save_item(NAME(m_zx)); + save_item(NAME(m_gzx)); + + save_item(NAME(m_run)); + save_item(NAME(m_not_rstb)); + save_item(NAME(m_not_load)); + save_item(NAME(m_not_zcint)); + save_item(NAME(m_not_wpe)); + save_item(NAME(m_new_addr)); - m_zx_timer = timer_alloc(FUNC(cmi01a_device::zx_timer_cb), this); - m_eosi_timer = timer_alloc(FUNC(cmi01a_device::eosi_timer_cb), this); - m_bcas_timer = timer_alloc(FUNC(cmi01a_device::bcas_tick), this); + save_item(NAME(m_tri)); + save_item(NAME(m_permit_eload)); + save_item(NAME(m_not_eload)); - m_zx_timer->adjust(attotime::never); - m_eosi_timer->adjust(attotime::never); + save_item(NAME(m_bcas_q1_enabled)); + save_item(NAME(m_bcas_q1)); + save_item(NAME(m_bcas_q2)); - m_stream = stream_alloc(0, 1, 44100); + save_item(NAME(m_env_dir)); + save_item(NAME(m_env)); + save_item(NAME(m_env_divider)); + save_item(NAME(m_ediv_out)); + save_item(NAME(m_envdiv_toggles)); + save_item(NAME(m_eclk)); + save_item(NAME(m_env_clk)); - m_ptm->set_external_clocks(clock() / 8, clock() / 4, clock() / 4); + save_item(NAME(m_wave_addr_lsb)); + save_item(NAME(m_wave_addr_msb)); + save_item(NAME(m_upper_wave_addr_load)); + save_item(NAME(m_wave_addr_msb_clock)); + save_item(NAME(m_run_load_xor)); + save_item(NAME(m_delayed_inverted_run_load)); + save_item(NAME(m_ptm_c1)); + save_item(NAME(m_ptm_o1)); + save_item(NAME(m_ptm_o2)); + save_item(NAME(m_ptm_o3)); + save_item(NAME(m_vol_latch)); + save_item(NAME(m_flt_latch)); + save_item(NAME(m_rp)); + save_item(NAME(m_ws)); + save_item(NAME(m_dir)); } void cmi01a_device::device_reset() @@ -186,499 +143,600 @@ void cmi01a_device::device_reset() m_ptm->set_g2(1); m_ptm->set_g3(1); - m_segment_cnt = 0; - m_new_addr = 0; + m_current_sample = 0x80; + + m_new_addr = false; m_vol_latch = 0; m_flt_latch = 0; m_rp = 0; m_ws = 0; m_dir = 0; m_env = 0; - m_pia0_cb2_state = 1; - m_bcas_q1_ticks = 2; - m_bcas_q1 = 0; - m_bcas_q2_ticks = 4; - m_bcas_q2 = 0; - m_zx_flag = 0; - - m_freq = 0.0; + m_bcas_q2 = false; + m_bcas_q1 = false; + m_not_rstb = true; m_ptm_o1 = 0; m_ptm_o2 = 0; m_ptm_o3 = 0; - m_load = true; m_run = false; m_gzx = true; - m_nwpe = true; - m_tri = true; - m_pia1_ca2 = false; + m_not_wpe = false; + m_tri = false; + m_permit_eload = false; m_eclk = false; m_env_clk = false; m_ediv_out = true; - m_ediv_rate = 3; - m_ediv_count = 0; + m_env_divider = 3; + std::fill(std::begin(m_envdiv_toggles), std::end(m_envdiv_toggles), false); m_pitch = 0; m_octave = 0; - m_zx_timer->adjust(attotime::never); - m_eosi_timer->adjust(attotime::never); - //m_bcas_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock())); - m_bcas_timer->adjust(attotime::never); + m_bcas_q1_timer->adjust(attotime::from_hz(clock() / 2), 0, attotime::from_hz(clock() / 2)); + m_zcint_pulse_timer->adjust(attotime::never); + m_rstb_pulse_timer->adjust(attotime::never); + m_sample_timer->adjust(attotime::never); } -void cmi01a_device::pulse_zcint() +void cmi01a_device::device_resolve_objects() { - m_pia[0]->ca1_w(0); - m_pia[0]->ca1_w(1); - - pulse_gzx(); + m_irq_cb.resolve_safe(); } -void cmi01a_device::pulse_gzx() +void cmi01a_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) { - if (!m_pia1_ca2) + if (m_run) { - return; - } + auto &buf = outputs[0]; - reset_waveform_segment(); - m_env = m_rp; - m_env_dir = m_dir; + for (int sampindex = 0; sampindex < buf.samples(); sampindex++) + { + const s32 sample = (s32)(s8)(m_current_sample ^ 0x80); + const s32 env32 = (s32)m_env; + const s32 vol32 = (s32)m_vol_latch; + const s16 sample16 = (s16)(u16)((sample * env32 * vol32) >> 8); + buf.put_int(sampindex, sample16, 32768); + } + } + else + { + outputs[0].fill(0); + } } -void cmi01a_device::reset_waveform_segment() +TIMER_CALLBACK_MEMBER(cmi01a_device::update_sample) { - m_segment_cnt &= 0x007f; - m_segment_cnt |= (0x4000 | (m_ws << 7)); + m_stream->update(); + m_current_sample = m_wave_ram[((m_wave_addr_msb << 7) | m_wave_addr_lsb) & 0x3fff]; + set_wave_addr_lsb((m_wave_addr_lsb + 1) & 0x7f); } -void cmi01a_device::load_w(int state) +int cmi01a_device::notload_r() { - const bool old_load = m_load; - m_load = state ? false : true; - - if (old_load != m_load) - { - check_segment_load(); - } + return m_not_load; } -void cmi01a_device::check_segment_load() +void cmi01a_device::notload_w(int state) { - bool run_strobe = false; - if (m_load != m_run) - { - run_strobe = true; - m_segment_cnt &= ~0x7f; - } - - if (!run_strobe) - { - return; - } - - if (!m_nwpe) - { - reset_waveform_segment(); - } - - if (m_channel == 5) LOG("CH%d beginning load with m_segment_cnt %04x\n", m_channel, m_segment_cnt); - m_pia[1]->cb1_w(1); + set_not_load(state); } -void cmi01a_device::pia_1_a_w(uint8_t data) +void cmi01a_device::pitch_octave_w(u8 data) { m_pitch &= 0x0ff; m_pitch |= (data & 3) << 8; m_octave = (data >> 2) & 0x0f; } -uint8_t cmi01a_device::pia_1_a_r() +u8 cmi01a_device::pitch_octave_r() { return ((m_pitch >> 8) & 3) | (m_octave << 2); } -void cmi01a_device::pia_1_b_w(uint8_t data) +void cmi01a_device::pitch_lsb_w(u8 data) { m_pitch &= 0xf00; m_pitch |= data; } -void cmi01a_device::rp_w(uint8_t data) +u8 cmi01a_device::pitch_lsb_r() +{ + return (u8)m_pitch; +} + +void cmi01a_device::rp_w(u8 data) { m_rp = data; - m_ediv_rate = ((m_rp >> 2) & 0x3c) | 0x03; - if (m_channel == 5) LOG("CH%d: Initial ramp value: %02x, EDIV divider: %02x\n", m_channel, data, m_ediv_rate); } -void cmi01a_device::ws_dir_w(uint8_t data) +u8 cmi01a_device::rp_r() +{ + return m_rp; +} + +void cmi01a_device::ws_dir_w(u8 data) { - if (m_channel == 5) LOG("CH%d: WS/DIR write: %02x\n", m_channel, data); m_ws = data & 0x7f; m_dir = (data >> 7) & 1; + try_load_upper_wave_addr(); } -uint8_t cmi01a_device::ws_dir_r() +u8 cmi01a_device::ws_dir_r() { return m_ws | (m_dir << 7); } -READ_LINE_MEMBER( cmi01a_device::tri_r ) +int cmi01a_device::tri_r() { - const bool top_terminal_count = (m_env_dir == ENV_DIR_UP && m_env == 0xff); - const bool bottom_terminal_count = (m_env_dir == ENV_DIR_DOWN && m_env == 0x00); - const int state = (top_terminal_count || bottom_terminal_count) ? 1 : 0; - if (m_channel == 5) LOG("CH%d: PIA0 CB1 Read (/TRI): %d\n", m_channel, state); - return state; + return m_tri; } -WRITE_LINE_MEMBER( cmi01a_device::cmi01a_irq ) +void cmi01a_device::cmi01a_irq(int state) { m_irq_cb(state ? ASSERT_LINE : CLEAR_LINE); } -void cmi01a_device::reset_bcas_counter() +void cmi01a_device::permit_eload_w(int state) { - m_bcas_q1_ticks = 2; - m_bcas_q1 = 0; - m_bcas_q2_ticks = 4; - m_bcas_q2 = 0; - - m_ptm->set_clock(0, 0); - m_ptm->set_clock(1, 0); - m_ptm->set_clock(2, 0); + m_permit_eload = state; + update_not_eload(); } -TIMER_CALLBACK_MEMBER(cmi01a_device::bcas_tick) +void cmi01a_device::run_voice() { - if (m_ptm_o1 != m_zx_ff) - return; - // TODO -} + double cfreq = ((0x800 | (m_pitch << 1)) * m_mosc) / 4096.0; -TIMER_CALLBACK_MEMBER(cmi01a_device::eosi_timer_cb) -{ - m_stream->update(); - m_segment_cnt &= ~0x4000; - m_pia[1]->cb1_w(0); + /* Octave register enabled? */ + if (!BIT(m_octave, 3)) + cfreq /= (double)(2 << ((7 ^ m_octave) & 7)); - if (m_channel == 5) LOG("CH%d: End of sound\n", m_channel); + cfreq /= 16.0; + + m_sample_timer->adjust(attotime::from_hz(cfreq), 0, attotime::from_hz(cfreq)); } -TIMER_CALLBACK_MEMBER(cmi01a_device::zx_timer_cb) +void cmi01a_device::run_w(int state) { - // Toggle ZX - m_zx_flag ^= 1; + bool old_run = m_run; + m_run = state; + + if (old_run != m_run) + update_rstb_pulser(); - // Update ZX input to PIA 1 - m_pia[1]->ca1_w(m_zx_flag); + m_stream->update(); - // 74LS74 A12 (1) is clocked by /ZX, so a 1->0 transition of the ZX flag is a positive clock transition - if (m_zx_flag == 0) + /* RUN */ + if (!old_run && m_run) { - // Pulse /ZCINT if the O1 output of the PTM has changed - if (m_ptm_o1 != m_zx_ff) - { - reset_bcas_counter(); - pulse_zcint(); - } + run_voice(); - m_zx_ff = m_ptm_o1; + m_ptm->set_g1(0); + m_ptm->set_g2(0); + m_ptm->set_g3(0); } - update_eclk(); + if (old_run && !m_run) + { + m_sample_timer->adjust(attotime::never); + m_current_sample = 0x80; + + m_ptm->set_g1(1); + m_ptm->set_g2(1); + m_ptm->set_g3(1); + + set_zx_flipflop_state(false); + } } -void cmi01a_device::update_eclk() +inline void cmi01a_device::update_rstb_pulser() { - bool eclk = (m_ptm_o2 && m_zx_ff) || (m_ptm_o3 && !m_zx_ff); - if (m_channel == 5) logerror("CH%d: eclk = (%d && %d) || (%d && %d) = %d\n", m_channel, m_ptm_o2, m_zx_ff, m_ptm_o3, m_zx_ff ? 0 : 1, eclk ? 1 : 0); - m_stream->update(); - set_eclk(eclk); + set_run_load_xor(m_run != !m_not_load); } -void cmi01a_device::wpe_w(int state) +void cmi01a_device::set_run_load_xor(const bool run_load_xor) { - m_nwpe = state ? false : true; + if (run_load_xor == m_run_load_xor) + return; + + m_run_load_xor = run_load_xor; + if (m_rstb_pulse_timer->remaining().is_never()) + { + m_rstb_pulse_timer->adjust(attotime::from_nsec(27500)); + m_new_addr = true; + } + else + { + m_rstb_pulse_timer->adjust(attotime::never); + } + set_not_rstb(m_run_load_xor != m_delayed_inverted_run_load); } -void cmi01a_device::eload_w(int state) +TIMER_CALLBACK_MEMBER(cmi01a_device::rstb_pulse_cb) { - if (m_channel == 5) LOG("CH%d PIA1 CA2: %d\n", m_channel, state); - m_pia1_ca2 = state; + m_delayed_inverted_run_load = !m_run_load_xor; + set_not_rstb(m_run_load_xor != m_delayed_inverted_run_load); } -void cmi01a_device::clock_envelope() +void cmi01a_device::set_not_rstb(const bool not_rstb) { - m_stream->update(); - const bool old_tri = m_tri; - if (m_env_dir == ENV_DIR_DOWN) + if (not_rstb == m_not_rstb) + return; + + m_not_rstb = not_rstb; + update_gzx(); + if (!m_not_rstb) { - if (m_env > 0) - { - m_env--; - m_ediv_rate = ((m_env >> 2) & 0x3c) | 0x03; - if (m_channel == 5) LOG("CH%d, Clocking envelope down, new rp: %02x\n", m_channel, m_env); - } - m_tri = m_env == 0x00; + set_wave_addr_lsb(0); + set_wave_addr_msb(0x80 | m_ws); } - else +} + +void cmi01a_device::update_bcas_q1_enable() +{ + const bool old_enable = m_bcas_q1_enabled; + m_bcas_q1_enabled = (m_zx_ff == m_ptm_o1); + + if (!old_enable && m_bcas_q1_enabled) { - if (m_env < 0xff) - { - m_env++; - m_ediv_rate = ((~m_env >> 2) & 0x3c) | 0x03; - if (m_channel == 5) LOG("CH%d, Clocking envelope up, new rp: %02x\n", m_channel, m_env); - } - m_tri = m_env == 0xff; + m_bcas_q1_timer->adjust(attotime::from_hz(clock() / 2), 0, attotime::from_hz(clock() / 2)); } - if (old_tri != m_tri) + else if (old_enable && !m_bcas_q1_enabled) { - m_pia[0]->cb1_w(m_tri ? 0 : 1); + m_bcas_q1_timer->adjust(attotime::never); } } -void cmi01a_device::tick_ediv() +TIMER_CALLBACK_MEMBER(cmi01a_device::bcas_q1_tick) { - if (m_channel == 5) logerror("CH%d ticking ediv, rate: %02x\n", m_channel, m_ediv_rate); - m_ediv_out = s_7497_rate_table[m_ediv_rate][m_ediv_count]; - m_ediv_count = (m_ediv_count + 1) & 0x3f; + const bool old_q1 = m_bcas_q1; + m_bcas_q1 = !m_bcas_q1; + m_ptm->set_c2(m_bcas_q1); + m_ptm->set_c3(m_bcas_q1); + if (old_q1 && !m_bcas_q1) + { + m_bcas_q2 = !m_bcas_q2; + update_ptm_c1(); + } } -void cmi01a_device::set_eclk(bool eclk) +void cmi01a_device::set_zx_flipflop_clock(const bool zx_ff_clk) { - bool old_eclk = m_eclk; - m_eclk = eclk; + if (zx_ff_clk == m_zx_ff_clk) + return; - if (old_eclk == m_eclk) + m_zx_ff_clk = zx_ff_clk; + + if (m_zx_ff_clk && m_run) + set_zx_flipflop_state(m_ptm_o1); +} + +void cmi01a_device::set_zx_flipflop_state(const bool zx_ff) +{ + if (zx_ff == m_zx_ff) return; - if (!old_eclk && m_eclk) - { - tick_ediv(); - } + m_zx_ff = zx_ff; - // A B !(A && B) !A || !B - // 0 0 1 1 - // 0 1 1 1 - // 1 0 1 1 - // 1 1 0 0 + update_bcas_q1_enable(); + pulse_zcint(); +} - const bool a = !m_load || !eclk; - const bool b = m_load || !m_ediv_out; +inline void cmi01a_device::pulse_zcint() +{ + set_not_zcint(false); + m_zcint_pulse_timer->adjust(attotime::from_nsec(2750)); +} - const bool old_env_clk = m_env_clk; - m_env_clk = !a || !b; - LOG("CH%d checking envelope: A: !!load(%d) || !eclk(%d) = %d\n", m_channel, m_load ? 0 : 1, eclk ? 0 : 1, a); - LOG("CH%d checking envelope: B: !load(%d) || !eout(%d) = %d\n", m_channel, m_load ? 1 : 0, m_ediv_out ? 0 : 1, b); - LOG("CH%d checking envelope: C: !%d || !%d = %d\n", m_channel, a ? 1 : 0, b ? 1 : 0, m_env_clk ? 1 : 0); - if (!old_env_clk && m_env_clk) - { - clock_envelope(); - } +TIMER_CALLBACK_MEMBER(cmi01a_device::zcint_pulse_cb) +{ + set_not_zcint(true); } -void cmi01a_device::run_voice() +void cmi01a_device::set_not_zcint(const bool not_zcint) { - if (m_channel == 5) LOG("CH%d running voice: Pitch = %04x\n", m_channel, (uint16_t)m_pitch); - if (m_channel == 5) LOG("CH%d running voice: o_val = %x\n", m_channel, m_octave); + if (not_zcint == m_not_zcint) + return; - int m_tune = m_cmi02_pia[0]->b_output(); - if (m_channel == 5) 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); - if (m_channel == 5) LOG("CH%d running voice: mfreq = %f (%03x * %f)\n", m_channel, mfreq, 0xf00 | m_tune, (MASTER_OSCILLATOR.dvalue() / 2.0) / 4096.0); + m_not_zcint = not_zcint; + m_pia[0]->ca1_w(not_zcint); + update_gzx(); +} - double cfreq = ((double)(0x800 | (m_pitch << 1)) * mfreq) / 4096.0; - if (m_channel == 5) LOG("CH%d running voice: cfreq = %f (%04x * %f) / 4096.0\n", m_channel, cfreq, 0x800 | (m_pitch << 1), mfreq, cfreq); +void cmi01a_device::set_not_load(const bool not_load) +{ + if (not_load == m_not_load) + return; - if (cfreq > MASTER_OSCILLATOR.dvalue()) - { - if (m_channel == 5) LOG("CH%d Ignoring voice run due to excessive frequency\n"); + m_not_load = not_load; + update_rstb_pulser(); + update_ptm_c1(); +} + +inline void cmi01a_device::update_gzx() +{ + set_gzx(!m_not_rstb || !m_not_zcint); +} + +void cmi01a_device::set_gzx(const bool gzx) +{ + if (gzx == m_gzx) return; - } - if (m_channel == 5) LOG("CH%d Running voice\n", m_channel); - /* Octave register enabled? */ - if (!BIT(m_octave, 3)) - cfreq /= (double)(2 << ((7 ^ m_octave) & 7)); + m_gzx = gzx; + update_upper_wave_addr_load(); + update_not_eload(); + if (m_gzx) + set_envelope_dir(m_dir); +} - cfreq /= 16.0; +inline void cmi01a_device::update_not_eload() +{ + set_not_eload(!(m_permit_eload && m_gzx)); +} - m_freq = cfreq; +void cmi01a_device::set_not_eload(const bool not_eload) +{ + if (not_eload == m_not_eload) + return; - if (m_channel == 5) LOG("CH%d running voice: Final freq: %f\n", m_channel, m_freq); + m_not_eload = not_eload; + try_load_envelope(); +} - m_stream->set_sample_rate(cfreq); +inline void cmi01a_device::try_load_envelope() +{ + if (m_not_eload) + return; - // Set timers and things - m_zx_flag = 0; - attotime zx_period = attotime::from_ticks(64, cfreq); - m_zx_timer->adjust(zx_period, 0, zx_period); + set_envelope(m_rp); +} - if (m_load) - { - int samples = 0x4000 - (m_segment_cnt & 0x3fff); - if (m_channel == 5) LOG("CH%d voice is %04x samples long\n", m_channel, samples); - m_eosi_timer->adjust(attotime::from_ticks(samples, cfreq)); - } +void cmi01a_device::set_envelope(const u8 env) +{ + if (env == m_env) + return; + + m_env = env; + update_envelope_divider(); + update_envelope_tri(); } -WRITE_LINE_MEMBER( cmi01a_device::pia_0_cb2_w ) +void cmi01a_device::update_envelope_divider() { - int old_state = m_pia0_cb2_state; - m_pia0_cb2_state = state; - if (m_channel == 5) LOG("CH%d PIA0 CB2: %d\n", m_channel, state); + if (m_env_dir == ENV_DIR_UP) + m_env_divider = (~m_env >> 2) & 0x3c; + else + m_env_divider = (m_env >> 2) & 0x3c; + m_env_divider |= 0x03; +} - m_stream->update(); +void cmi01a_device::set_envelope_dir(const int env_dir) +{ + if (env_dir == m_env_dir) + return; - /* RUN */ - if (!old_state && m_pia0_cb2_state) - { - m_run = true; + m_env_dir = env_dir; + update_envelope_divider(); + update_envelope_tri(); +} - /* Clear /EOSI */ - m_pia[1]->cb1_w(1); +void cmi01a_device::update_envelope_clock() +{ + const bool old_eclk = m_eclk; + m_eclk = (m_ptm_o2 && m_zx_ff) || (m_ptm_o3 && !m_zx_ff); - /* Only reset address counter if LOAD not asserted */ - if (!m_load) - { - m_segment_cnt = 0x4000 | (m_ws << 7); - m_new_addr = 1; - } + if (old_eclk == m_eclk) + return; + + tick_ediv(); - /* Clear ZX */ - m_pia[1]->ca1_w(0); + const bool old_env_clk = m_env_clk; + m_env_clk = ((m_not_load && m_eclk) || (!m_not_load && m_ediv_out)); - /* Clear /ZCINT */ - m_pia[0]->ca1_w(1); + if (!old_env_clk && m_env_clk) + clock_envelope(); +} - m_ptm->set_g1(0); - m_ptm->set_g2(0); - m_ptm->set_g3(0); +void cmi01a_device::clock_envelope() +{ + if (m_tri) + return; - run_voice(); - } + m_stream->update(); + if (m_env_dir == ENV_DIR_DOWN) + m_env--; + else + m_env++; + update_envelope_divider(); + update_envelope_tri(); +} - if (old_state && !m_pia0_cb2_state) - { - m_run = false; +void cmi01a_device::tick_ediv() +{ + const bool envdiv_enable_a = m_eclk; + const bool envdiv_enable_b = m_eclk && m_envdiv_toggles[0]; + const bool envdiv_enable_c = m_eclk && m_envdiv_toggles[0] && m_envdiv_toggles[1]; + const bool envdiv_enable_d = m_eclk && m_envdiv_toggles[0] && m_envdiv_toggles[1] && m_envdiv_toggles[2]; + const bool envdiv_enable_e = m_eclk && m_envdiv_toggles[0] && m_envdiv_toggles[1] && m_envdiv_toggles[2] && m_envdiv_toggles[3]; + const bool envdiv_enable_f = m_eclk && m_envdiv_toggles[0] && m_envdiv_toggles[1] && m_envdiv_toggles[2] && m_envdiv_toggles[3] && m_envdiv_toggles[4]; + + if (envdiv_enable_f) + m_envdiv_toggles[5] = !m_envdiv_toggles[5]; + if (envdiv_enable_e) + m_envdiv_toggles[4] = !m_envdiv_toggles[4]; + if (envdiv_enable_d) + m_envdiv_toggles[3] = !m_envdiv_toggles[3]; + if (envdiv_enable_c) + m_envdiv_toggles[2] = !m_envdiv_toggles[2]; + if (envdiv_enable_b) + m_envdiv_toggles[1] = !m_envdiv_toggles[1]; + if (envdiv_enable_a) + m_envdiv_toggles[0] = !m_envdiv_toggles[0]; + + const bool envdiv_out_f = m_eclk && BIT(m_env_divider, 5) && !m_envdiv_toggles[0]; + const bool envdiv_out_e = m_eclk && BIT(m_env_divider, 4) && m_envdiv_toggles[0] && !m_envdiv_toggles[1]; + const bool envdiv_out_d = m_eclk && BIT(m_env_divider, 3) && m_envdiv_toggles[0] && m_envdiv_toggles[1] && !m_envdiv_toggles[2]; + const bool envdiv_out_c = m_eclk && BIT(m_env_divider, 2) && m_envdiv_toggles[0] && m_envdiv_toggles[1] && m_envdiv_toggles[2] && !m_envdiv_toggles[3]; + const bool envdiv_out_b = m_eclk && BIT(m_env_divider, 1) && m_envdiv_toggles[0] && m_envdiv_toggles[1] && m_envdiv_toggles[2] && m_envdiv_toggles[3] && !m_envdiv_toggles[4]; + const bool envdiv_out_a = m_eclk && BIT(m_env_divider, 0) && m_envdiv_toggles[0] && m_envdiv_toggles[1] && m_envdiv_toggles[2] && m_envdiv_toggles[3] && m_envdiv_toggles[4] && !m_envdiv_toggles[5]; + + m_ediv_out = !(envdiv_out_f || envdiv_out_e || envdiv_out_d || envdiv_out_c || envdiv_out_b || envdiv_out_a); +} + +void cmi01a_device::update_envelope_tri() +{ + if (m_env_dir == ENV_DIR_DOWN) + m_tri = (m_env == 0x00); + else + m_tri = (m_env == 0xff); - /* Set /EOSI */ - m_pia[1]->cb1_w(0); + m_pia[0]->cb1_w(m_tri); +} - m_ptm->set_g1(1); - m_ptm->set_g2(1); - m_ptm->set_g3(1); +void cmi01a_device::not_wpe_w(int state) +{ + if (state == m_not_wpe) + return; - m_zx_timer->adjust(attotime::never); - m_eosi_timer->adjust(attotime::never); - m_zx_ff = 0; - } + m_not_wpe = state; + update_upper_wave_addr_load(); +} +inline void cmi01a_device::update_upper_wave_addr_load() +{ + const bool c10_and_out = (!m_not_wpe && m_gzx); + set_upper_wave_addr_load(c10_and_out || !m_not_rstb); } -void cmi01a_device::update_wave_addr(int inc) +inline void cmi01a_device::set_upper_wave_addr_load(const bool upper_wave_addr_load) { - int old_cnt = m_segment_cnt; + if (upper_wave_addr_load == m_upper_wave_addr_load) + return; - if (inc) - ++m_segment_cnt; + m_upper_wave_addr_load = upper_wave_addr_load; + try_load_upper_wave_addr(); +} - /* Update end of sound interrupt flag */ - m_pia[1]->cb1_w((m_segment_cnt & 0x4000) >> 14); +inline void cmi01a_device::try_load_upper_wave_addr() +{ + if (!m_upper_wave_addr_load) + return; - /* TODO Update zero crossing flag */ - m_pia[1]->ca1_w((m_segment_cnt & 0x40) >> 6); + set_wave_addr_msb(0x80 | m_ws); +} - /* Clock a latch on a transition */ - if ((old_cnt & 0x40) && !(m_segment_cnt & 0x40)) - { - m_pia[1]->ca2_w(1); - m_pia[1]->ca2_w(0); - } +void cmi01a_device::set_wave_addr_lsb(const u8 wave_addr_lsb) +{ + if (wave_addr_lsb == m_wave_addr_lsb) + return; - /* Zero crossing interrupt is a pulse */ + m_wave_addr_lsb = wave_addr_lsb; + set_zx(BIT(m_wave_addr_lsb, 6)); } -WRITE_LINE_MEMBER( cmi01a_device::ptm_irq ) +void cmi01a_device::set_wave_addr_msb(const u8 wave_addr_msb) { - m_irq_merger->in_w<4>(state); + if (wave_addr_msb == m_wave_addr_msb) + return; + + m_wave_addr_msb = wave_addr_msb; + m_pia[1]->cb1_w(BIT(m_wave_addr_msb, 7)); } -WRITE_LINE_MEMBER( cmi01a_device::ptm_o1 ) +void cmi01a_device::set_wave_addr_msb_clock(const bool wave_addr_msb_clock) +{ + if (wave_addr_msb_clock == m_wave_addr_msb_clock) + return; + + m_wave_addr_msb_clock = wave_addr_msb_clock; + if (m_wave_addr_msb_clock) + set_wave_addr_msb(m_wave_addr_msb + 1); +} + +void cmi01a_device::set_zx(const bool zx) +{ + if (zx == m_zx) + return; + + m_zx = zx; + set_wave_addr_msb_clock(!(!m_not_load && m_zx)); + m_pia[1]->ca1_w(m_zx); + set_zx_flipflop_clock(!m_zx); + update_ptm_c1(); +} + +void cmi01a_device::update_ptm_c1() +{ + const bool old_ptm_c1 = m_ptm_c1; + m_ptm_c1 = (m_not_load && m_bcas_q2) || (!m_not_load && !m_zx); + if (old_ptm_c1 != m_ptm_c1) + m_ptm->set_c1(m_ptm_c1); +} + +void cmi01a_device::ptm_o1(int state) { m_ptm_o1 = state; - if (m_ptm_o1 != m_zx_ff) - reset_bcas_counter(); - update_eclk(); + update_bcas_q1_enable(); } -WRITE_LINE_MEMBER( cmi01a_device::ptm_o2 ) +void cmi01a_device::ptm_o2(int state) { m_ptm_o2 = state; - update_eclk(); + update_envelope_clock(); } -WRITE_LINE_MEMBER( cmi01a_device::ptm_o3 ) +void cmi01a_device::ptm_o3(int state) { m_ptm_o3 = state; - update_eclk(); + update_envelope_clock(); } -READ_LINE_MEMBER( cmi01a_device::eosi_r ) +int cmi01a_device::eosi_r() { - if (m_channel == 5) LOG("CH%d PIA1 CB1 Read: %d\n", m_channel, BIT(m_segment_cnt, 14)); - return BIT(m_segment_cnt, 14); + return BIT(m_wave_addr_msb, 7); } -READ_LINE_MEMBER( cmi01a_device::zx_r ) +int cmi01a_device::zx_r() { - return (m_segment_cnt & 0x40) >> 6; + return BIT(m_wave_addr_lsb, 6); } -void cmi01a_device::write(offs_t offset, uint8_t data) +void cmi01a_device::write(offs_t offset, u8 data) { switch (offset) { case 0x0: - if (m_channel == 5) LOG("%s: CH%d Porthole Write to %04x: %02x\n", machine().describe_context(), m_channel, m_segment_cnt & 0x3fff, data); if (m_new_addr) - m_new_addr = 0; + m_new_addr = false; - m_wave_ram[m_segment_cnt & 0x3fff] = data; - update_wave_addr(1); + m_wave_ram[((m_wave_addr_msb << 7) | m_wave_addr_lsb) & 0x3fff] = data; + set_wave_addr_lsb((m_wave_addr_lsb + 1) & 0x7f); break; case 0x3: - if (m_channel == 5) LOG("%s: CH%d set Envelope Dir Down (%02x)\n", machine().describe_context(), m_channel, data); - m_env_dir = ENV_DIR_DOWN; + set_envelope_dir(ENV_DIR_DOWN); break; case 0x4: - if (m_channel == 5) LOG("%s: CH%d set Envelope Dir Up (%02x)\n", machine().describe_context(), m_channel, data); - m_env_dir = ENV_DIR_UP; + set_envelope_dir(ENV_DIR_UP); break; case 0x5: - if (m_channel == 5) LOG("%s: CH%d set Volume Latch: %02x\n", machine().describe_context(), m_channel, data); m_vol_latch = data; break; case 0x6: - if (m_channel == 5) LOG("%s: CH%d set Filter Latch: %02x\n", machine().describe_context(), m_channel, data); m_flt_latch = data; break; case 0x8: case 0x9: case 0xa: case 0xb: - if (m_channel == 5) 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: - if (m_channel == 5) 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; @@ -689,63 +747,52 @@ 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); - if ((offset == 5 || offset == 7) && (data < 0x30)) - data = 0xff; - - if (m_channel == 5) 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; } default: - if (m_channel == 5) LOG("%s: Unknown channel card write to E0%02X = %02X\n", machine().describe_context(), offset, data); + LOG("%s: Unknown channel card write to E0%02X = %02X\n", machine().describe_context(), offset, data); break; } } -uint8_t cmi01a_device::read(offs_t offset) +u8 cmi01a_device::read(offs_t offset) { if (machine().side_effects_disabled()) return 0; - uint8_t data = 0; + u8 data = 0; switch (offset) { case 0x0: - if (m_new_addr) + data = m_wave_ram[((m_wave_addr_msb << 7) | m_wave_addr_lsb) & 0x3fff]; + if (!m_new_addr) { - m_new_addr = 0; - break; + set_wave_addr_lsb((m_wave_addr_lsb + 1) & 0x7f); } - data = m_wave_ram[m_segment_cnt & 0x3fff]; - if (m_channel == 5) LOG("%s: CH%d Porthole Read: %02x\n", machine().describe_context(), m_channel, data); - update_wave_addr(1); + m_new_addr = false; break; case 0x3: - if (m_channel == 5) LOG("%s: CH%d set Envelope Dir Down (R)\n", machine().describe_context(), m_channel); - m_env_dir = ENV_DIR_DOWN; + set_envelope_dir(ENV_DIR_DOWN); break; case 0x4: - if (m_channel == 5) LOG("%s: CH%d set Envelope Dir Up (R)\n", machine().describe_context(), m_channel); - m_env_dir = ENV_DIR_UP; + set_envelope_dir(ENV_DIR_UP); break; case 0x5: - if (m_channel == 5) LOG("%s: CH%d read Volume Latch (ff)\n", machine().describe_context(), m_channel); data = 0xff; break; case 0x8: case 0x9: case 0xa: case 0xb: data = m_pia[0]->read(offset & 3); - if (m_channel == 5) 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)); - if (m_channel == 5) 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: @@ -756,16 +803,13 @@ uint8_t cmi01a_device::read(offs_t offset) data = m_ptm->read((a2 << 2) | (a1 << 1) | a0); - if (m_channel == 5) LOG("CH%d PTM Read: %d = %02x\n", m_channel, (a2 << 2) | (a1 << 1) | a0, data); break; } default: - if (m_channel == 5) LOG("%s: Unknown channel card %d read from E0%02X\n", machine().describe_context(), m_channel, offset); + LOG("%s: Unknown channel card %d read from E0%02X\n", machine().describe_context(), m_channel, offset); break; } - if (m_channel == 5) LOG("%s: channel card %d read: %02x = %02x\n", machine().describe_context(), m_channel, offset, data); - return data; } diff --git a/src/mame/fairlight/cmi01a.h b/src/mame/fairlight/cmi01a.h index a884b568ace..84179ece3f7 100644 --- a/src/mame/fairlight/cmi01a.h +++ b/src/mame/fairlight/cmi01a.h @@ -13,29 +13,25 @@ #include "machine/6840ptm.h" #include "machine/input_merger.h" -#define ENV_DIR_UP 0 -#define ENV_DIR_DOWN 1 - -#define CHANNEL_STATUS_LOAD 1 -#define CHANNEL_STATUS_RUN 2 - class cmi01a_device : public device_t, public device_sound_interface { public: - cmi01a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, uint32_t channel) + cmi01a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, u32 channel) : cmi01a_device(mconfig, tag, owner, clock) { m_channel = channel; } - cmi01a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + cmi01a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); auto irq_callback() { return m_irq_cb.bind(); } - void write(offs_t offset, uint8_t data); - uint8_t read(offs_t offset); + void write(offs_t offset, u8 data); + u8 read(offs_t offset); virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; + void set_master_osc(double mosc) { m_mosc = mosc; } + protected: virtual void device_resolve_objects() override; virtual void device_start() override; @@ -46,102 +42,147 @@ protected: required_device_array m_pia; required_device m_ptm; - required_device_array m_cmi02_pia; - sound_stream* m_stream; private: - DECLARE_WRITE_LINE_MEMBER(cmi01a_irq); + enum : int + { + ENV_DIR_UP, + ENV_DIR_DOWN + }; + + void cmi01a_irq(int state); + + TIMER_CALLBACK_MEMBER(update_sample); + + void notload_w(int state); + int notload_r(); + + void run_voice(); - TIMER_CALLBACK_MEMBER(bcas_tick); - void reset_bcas_counter(); + void rp_w(u8 data); + u8 rp_r(); + void ws_dir_w(u8 data); + u8 ws_dir_r(); + int tri_r(); + void run_w(int state); + void permit_eload_w(int state); + + int eosi_r(); + int zx_r(); + u8 pitch_octave_r(); + void pitch_octave_w(u8 data); + u8 pitch_lsb_r(); + void pitch_lsb_w(u8 data); + + void ptm_o1(int state); + void ptm_o2(int state); + void ptm_o3(int state); + + // New functions below this line + void update_rstb_pulser(); + void set_run_load_xor(const bool run_load_xor); + TIMER_CALLBACK_MEMBER(rstb_pulse_cb); + void set_not_rstb(const bool not_rstb); + + void update_bcas_q1_enable(); + TIMER_CALLBACK_MEMBER(bcas_q1_tick); + + void set_zx_flipflop_clock(const bool zx_ff_clk); + void set_zx_flipflop_state(const bool zx_ff); + void pulse_zcint(); + TIMER_CALLBACK_MEMBER(zcint_pulse_cb); + void set_not_zcint(const bool not_zcint); + + void set_not_load(const bool not_load); + + void update_gzx(); + void set_gzx(const bool gzx); + + void update_not_eload(); + void set_not_eload(const bool not_eload); + void try_load_envelope(); + void set_envelope(const u8 env); + void update_envelope_divider(); + void set_envelope_dir(const int env_dir); + void update_envelope_clock(); void clock_envelope(); void tick_ediv(); - void set_eclk(bool eclk); - void update_eclk(); - void pulse_zcint(); - void pulse_gzx(); - void reset_waveform_segment(); - void check_segment_load(); - void wpe_w(int state); - void load_w(int state); - - TIMER_CALLBACK_MEMBER(zx_timer_cb); - TIMER_CALLBACK_MEMBER(eosi_timer_cb); - void run_voice(); - void update_wave_addr(int inc); - - uint32_t m_channel; - emu_timer * m_zx_timer = nullptr; - uint8_t m_zx_flag = 0; - uint8_t m_zx_ff = 0; - - emu_timer * m_eosi_timer = nullptr; - - emu_timer * m_bcas_timer = nullptr; - - std::unique_ptr m_wave_ram; - uint16_t m_segment_cnt = 0; - uint8_t m_new_addr = 0; // Flag - uint8_t m_vol_latch = 0; - uint8_t m_flt_latch = 0; - uint8_t m_rp = 0; - uint8_t m_ws = 0; - int m_dir = 0; - int m_env_dir = 0; - uint8_t m_env = 0; - int m_pia0_cb2_state = 0; - - uint8_t m_bcas_q1_ticks = 0; - uint8_t m_bcas_q1 = 0; - uint8_t m_bcas_q2_ticks = 0; - uint8_t m_bcas_q2 = 0; - - double m_freq = 0; - - int m_ptm_o1 = 0; - int m_ptm_o2 = 0; - int m_ptm_o3 = 0; - - bool m_load = 0; - bool m_run = 0; - bool m_gzx = 0; - bool m_nwpe = 0; - bool m_tri = 0; - bool m_pia1_ca2 = 0; - - bool m_eclk = false; - bool m_env_clk = false; - bool m_ediv_out = false; - uint8_t m_ediv_rate = 0; - uint8_t m_ediv_count = 0; - - uint16_t m_pitch = 0; - uint8_t m_octave = 0; + void update_envelope_tri(); + void not_wpe_w(int state); + void update_upper_wave_addr_load(); + void set_upper_wave_addr_load(const bool upper_wave_addr_load); + void try_load_upper_wave_addr(); + void set_wave_addr_lsb(const u8 wave_addr_lsb); + void set_wave_addr_msb(const u8 wave_addr_msb); + void set_wave_addr_msb_clock(const bool wave_addr_msb_clock); + + void set_zx(const bool zx); + void update_ptm_c1(); + + u32 m_channel; + + emu_timer * m_zcint_pulse_timer = nullptr; + emu_timer * m_rstb_pulse_timer = nullptr; + emu_timer * m_bcas_q1_timer = nullptr; + emu_timer * m_sample_timer = nullptr; devcb_write_line m_irq_cb; - void rp_w(uint8_t data); - void ws_dir_w(uint8_t data); - uint8_t ws_dir_r(); - DECLARE_READ_LINE_MEMBER( tri_r ); - DECLARE_WRITE_LINE_MEMBER( pia_0_cb2_w ); - DECLARE_WRITE_LINE_MEMBER( eload_w ); - - DECLARE_READ_LINE_MEMBER( eosi_r ); - DECLARE_READ_LINE_MEMBER( zx_r ); - uint8_t pia_1_a_r(); - void pia_1_a_w(uint8_t data); - void pia_1_b_w(uint8_t data); - - DECLARE_WRITE_LINE_MEMBER( ptm_o1 ); - DECLARE_WRITE_LINE_MEMBER( ptm_o2 ); - DECLARE_WRITE_LINE_MEMBER( ptm_o3 ); - DECLARE_WRITE_LINE_MEMBER( ptm_irq ); - - static const uint8_t s_7497_rate_table[64][64]; + std::unique_ptr m_wave_ram; + u8 m_current_sample = 0; + + double m_mosc = 0.0; + u16 m_pitch = 0; + u8 m_octave = 0; + + bool m_zx_ff_clk = false; + bool m_zx_ff = false; + bool m_zx = false; + bool m_gzx = false; + + bool m_run = false; + bool m_not_rstb = true; + bool m_not_load = false; + bool m_not_zcint = true; + bool m_not_wpe = true; + bool m_new_addr = false; + + bool m_tri = false; + bool m_permit_eload = false; + bool m_not_eload = true; + + bool m_bcas_q1_enabled = true; + bool m_bcas_q1 = false; + bool m_bcas_q2 = false; + + int m_env_dir = 0; + u8 m_env = 0; + u8 m_env_divider = 0; + bool m_ediv_out = false; + bool m_envdiv_toggles[6]; + bool m_eclk = false; + bool m_env_clk = false; + + u8 m_wave_addr_lsb = 0; + u8 m_wave_addr_msb = 0; + bool m_upper_wave_addr_load = false; + bool m_wave_addr_msb_clock = true; + bool m_run_load_xor = true; + bool m_delayed_inverted_run_load = false; + + bool m_ptm_c1 = false; + bool m_ptm_o1 = false; + bool m_ptm_o2 = false; + bool m_ptm_o3 = false; + + u8 m_vol_latch = 0; + u8 m_flt_latch = 0; + u8 m_rp = 0; + u8 m_ws = 0; + int m_dir = 0; }; // device type definition diff --git a/src/mame/fairlight/cmi_mkbd.cpp b/src/mame/fairlight/cmi_mkbd.cpp index f4b3a2a987a..63aae713a86 100644 --- a/src/mame/fairlight/cmi_mkbd.cpp +++ b/src/mame/fairlight/cmi_mkbd.cpp @@ -38,6 +38,9 @@ #include "cpu/m6800/m6800.h" #include "machine/clock.h" +#define VERBOSE (0) +#include "logmacro.h" + DEFINE_DEVICE_TYPE(CMI_MUSIC_KEYBOARD, cmi_music_keyboard_device, "cmi_mkbd", "Fairlight CMI Music Keyboard") cmi_music_keyboard_device::cmi_music_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) @@ -77,6 +80,12 @@ void cmi_music_keyboard_device::device_start() m_cmi10_scnd_timer->adjust(attotime::from_hz(4000000 / 4 / 2048 / 2), 0, attotime::from_hz(4000000 / 4 / 2048 / 2)); m_scnd = 0; + + for (u32 i = 0; i < KEY_COUNT; i++) + { + m_velocity_timers[i] = timer_alloc(FUNC(cmi_music_keyboard_device::velkey_down), this); + m_key_held[i] = false; + } } TIMER_CALLBACK_MEMBER(cmi_music_keyboard_device::scnd_update) @@ -86,6 +95,11 @@ TIMER_CALLBACK_MEMBER(cmi_music_keyboard_device::scnd_update) m_cmi10_pia_u21->ca1_w(m_scnd); } +TIMER_CALLBACK_MEMBER(cmi_music_keyboard_device::velkey_down) +{ + m_key_held[param] = true; +} + /* PA0-7 = BKA0-7 (display) @@ -179,6 +193,18 @@ WRITE_LINE_MEMBER( cmi_music_keyboard_device::cmi10_u21_cb2_w ) // state = state; } +u32 cmi_music_keyboard_device::get_key_for_indices(int mux, int module, int key) +{ + if (mux == 3) + { + if (module == 2) + { + return KEY_F6; + } + return KEY_COUNT; + } + return KEY_F0 + (module * 24) + (mux * 8) + key; +} u8 cmi_music_keyboard_device::cmi10_u21_a_r() { @@ -225,15 +251,37 @@ u8 cmi_music_keyboard_device::cmi10_u21_a_r() return data; #else + int thld = m_cmi10_pia_u21->ca2_output(); int sel = m_cmi10_pia_u20->a_output(); int key = sel & 7; int mux = (sel >> 3) & 3; - u8 data = 0xf8; // slave keyboard not used + u8 data = 0xff; // slave keyboard not used for (int module = 0; module < 3; ++module) { u8 keyval = m_key_mux_ports[mux][module]->read(); - data |= BIT(keyval, key) << module; + u32 keyidx = get_key_for_indices(mux, module, key); + if (keyidx < KEY_COUNT) + { + if (m_key_held[keyidx]) + { + // Key is fully pressed + data &= ~(1 << module); + } + else if (!BIT(keyval, key)) + { + // User has started pressing the key + if (m_velocity_timers[keyidx]->remaining().is_never()) + { + data &= ~(1 << module); + m_velocity_timers[keyidx]->adjust(attotime::from_hz(10), keyidx); + } + else if (thld == 0) + { + data &= ~(1 << module); + } + } + } } /* Now do KD7 */ @@ -245,10 +293,10 @@ u8 cmi_music_keyboard_device::cmi10_u21_a_r() else if (!BIT(sel, 4)) bit = BIT(m_keypad_b_port->read(), sel & 7); - data |= (bit && BIT(sel, 7)) << 7; + data &= ~((bit && BIT(sel, 7)) << 7); } - return data; + return ~data; #endif } @@ -312,12 +360,35 @@ WRITE_LINE_MEMBER( cmi_music_keyboard_device::kbd_cts_w ) m_acia_kbd->write_cts(state); } +void cmi_music_keyboard_device::kbd_acia_w(offs_t offset, u8 data) +{ + m_acia_kbd->write(offset, data); + LOG("%s: music keyboard ACIA write: %02x = %02x\n", machine().describe_context(), offset, data); +} + +u8 cmi_music_keyboard_device::kbd_acia_r(offs_t offset) +{ + u8 data = m_acia_kbd->read(offset); + LOG("%s: music keyboard ACIA read: %02x: %02x\n", machine().describe_context(), offset, data); + return data; +} + +INPUT_CHANGED_MEMBER(cmi_music_keyboard_device::key_changed) +{ + if (newval) + { + // Key released + m_velocity_timers[param]->adjust(attotime::never); + } + m_key_held[param] = false; +} + void cmi_music_keyboard_device::muskeys_map(address_map &map) { map.unmap_value_high(); map(0x0080, 0x0083).rw(m_cmi10_pia_u21, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); map(0x0090, 0x0093).rw(m_cmi10_pia_u20, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); - map(0x00a0, 0x00a1).rw(m_acia_kbd, FUNC(acia6850_device::read), FUNC(acia6850_device::write)); + map(0x00a0, 0x00a1).rw(FUNC(cmi_music_keyboard_device::kbd_acia_r), FUNC(cmi_music_keyboard_device::kbd_acia_w)); map(0x00b0, 0x00b1).rw(m_acia_cmi, FUNC(acia6850_device::read), FUNC(acia6850_device::write)); map(0x4000, 0x47ff).ram(); map(0xb000, 0xb400).rom(); @@ -327,124 +398,124 @@ void cmi_music_keyboard_device::muskeys_map(address_map &map) static INPUT_PORTS_START(cmi_music_keyboard) /* Keypad */ PORT_START("KEYPAD_A") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) - PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1_PAD) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2_PAD) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3_PAD) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_4_PAD) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5_PAD) + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_6_PAD) + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_7_PAD) + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_8_PAD) PORT_START("KEYPAD_B") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) - PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_9_PAD) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_0_PAD) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1_PAD) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2_PAD) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3_PAD) + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_4_PAD) + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5_PAD) + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_6_PAD) /* Master musical keyboard */ PORT_START("KEY_0_0") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F0") - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F0 #") - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G0") - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G0 #") - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A1") - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A1 #") - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B1") - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F0") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_F0) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F0 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_F0S) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G0") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_G0) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G0 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_G0S) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A1") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_A1) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A1 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_A1S) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("B1") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_B1) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C1") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_C1) PORT_START("KEY_0_1") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C1 #") - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D1") - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D1 #") - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E1") - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F1") - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F1 #") - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G1") - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G1 #") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C1 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_C1S) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D1") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_D1) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D1 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_D1S) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("E1") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_E1) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F1") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_F1) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F1 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_F1S) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G1") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_G1) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G1 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_G1S) PORT_START("KEY_0_2") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A2") - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A2 #") - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B2") - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C2") - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C2 #") - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D2") - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D2 #") - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E2") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A2") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_A2) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A2 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_A2S) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("B2") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_B2) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C2") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_C2) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C2 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_C2S) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D2") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_D2) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D2 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_D2S) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("E2") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_E2) PORT_START("KEY_0_3") PORT_BIT(0xff, IP_ACTIVE_LOW, IPT_UNUSED) PORT_START("KEY_1_0") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F2") - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F2 #") - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G2") - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G2 #") - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A3") - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A3 #") - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B3") - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C3") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F2") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_F2) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F2 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_F2S) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G2") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_G2) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G2 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_G2S) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A3") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_A3) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A3 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_A3S) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("B3") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_B3) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C3") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_C3) PORT_START("KEY_1_1") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C3 #") - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D3") - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D3 #") - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E3") - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F3") - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G3") - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G3 #") - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C3 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_C3S) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D3") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_D3) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D3 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_D3S) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("E3") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_E3) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F3") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_F3) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F3 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_F3S) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G3") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_G3) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G3 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_G3S) PORT_START("KEY_1_2") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A4 #") - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B4") - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B4 #") - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C4") - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C4 #") - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D4") - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D4 #") - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A4") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_A4) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A4 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_A4S) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("B4") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_B4) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C4") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_C4) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C4 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_C4S) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D4") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_D4) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D4 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_D4S) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("E4") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_E4) PORT_START("KEY_1_3") PORT_BIT(0xff, IP_ACTIVE_LOW, IPT_UNUSED) PORT_START("KEY_2_0") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F4") - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F4 #") - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G4") - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G4 #") - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A5") - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A5 #") - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B5") - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C5") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F4") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_F4) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F4 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_F4S) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G4") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_G4) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G4 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_G4S) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A5") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_A5) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A5 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_A5S) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("B5") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_B5) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C5") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_C5) PORT_START("KEY_2_1") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C5 #") - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D5") - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D5 #") - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E5") - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F5") - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F5 #") - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G5") - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G5 #") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C5 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_C5S) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D5") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_D5) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D5 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_D5S) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("E5") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_E5) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F5") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_F5) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F5 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_F5S) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G5") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_G5) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G5 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_G5S) PORT_START("KEY_2_2") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A6") - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A6 #") - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B6") - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C6") - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C6 #") - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D6") - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D6 #") - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E6") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A6") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_A6) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A6 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_A6S) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("B6") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_B6) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C6") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_C6) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C6 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_C6S) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D6") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_D6) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D6 #") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_D6S) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("E6") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_E6) PORT_START("KEY_2_3") - PORT_BIT(0xff, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F6") + PORT_BIT(0xff, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F6") PORT_CHANGED_MEMBER(DEVICE_SELF, cmi_music_keyboard_device, key_changed, cmi_music_keyboard_device::KEY_F6) PORT_START("ANALOG") PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_MINMAX(0, 128) PORT_SENSITIVITY(100) PORT_KEYDELTA(50) diff --git a/src/mame/fairlight/cmi_mkbd.h b/src/mame/fairlight/cmi_mkbd.h index 8891f0cd090..5f8c76e3eab 100644 --- a/src/mame/fairlight/cmi_mkbd.h +++ b/src/mame/fairlight/cmi_mkbd.h @@ -30,6 +30,87 @@ public: DECLARE_WRITE_LINE_MEMBER( kbd_rxd_w ); DECLARE_WRITE_LINE_MEMBER( kbd_cts_w ); + DECLARE_INPUT_CHANGED_MEMBER(key_changed); + + enum : u32 + { + KEY_F0, + KEY_F0S, + KEY_G0, + KEY_G0S, + KEY_A1, + KEY_A1S, + KEY_B1, + KEY_C1, + KEY_C1S, + KEY_D1, + KEY_D1S, + KEY_E1, + KEY_F1, + KEY_F1S, + KEY_G1, + KEY_G1S, + KEY_A2, + KEY_A2S, + KEY_B2, + KEY_C2, + KEY_C2S, + KEY_D2, + KEY_D2S, + KEY_E2, + KEY_F2, + KEY_F2S, + KEY_G2, + KEY_G2S, + KEY_A3, + KEY_A3S, + KEY_B3, + KEY_C3, + KEY_C3S, + KEY_D3, + KEY_D3S, + KEY_E3, + KEY_F3, + KEY_F3S, + KEY_G3, + KEY_G3S, + KEY_A4, + KEY_A4S, + KEY_B4, + KEY_C4, + KEY_C4S, + KEY_D4, + KEY_D4S, + KEY_E4, + KEY_F4, + KEY_F4S, + KEY_G4, + KEY_G4S, + KEY_A5, + KEY_A5S, + KEY_B5, + KEY_C5, + KEY_C5S, + KEY_D5, + KEY_D5S, + KEY_E5, + KEY_F5, + KEY_F5S, + KEY_G5, + KEY_G5S, + KEY_A6, + KEY_A6S, + KEY_B6, + KEY_C6, + KEY_C6S, + KEY_D6, + KEY_D6S, + KEY_E6, + KEY_F6, + + KEY_COUNT + }; + protected: virtual const tiny_rom_entry *device_rom_region() const override; virtual void device_add_mconfig(machine_config &config) override; @@ -38,8 +119,12 @@ protected: virtual void device_start() override; TIMER_CALLBACK_MEMBER(scnd_update); + TIMER_CALLBACK_MEMBER(velkey_down); private: + void kbd_acia_w(offs_t offset, u8 data); + u8 kbd_acia_r(offs_t offset); + void cmi10_u20_a_w(u8 data); void cmi10_u20_b_w(u8 data); DECLARE_READ_LINE_MEMBER( cmi10_u20_cb1_r ); @@ -47,6 +132,8 @@ private: DECLARE_WRITE_LINE_MEMBER( cmi10_u21_cb2_w ); u8 cmi10_u21_a_r(); + u32 get_key_for_indices(int mux, int module, int key); + DECLARE_WRITE_LINE_MEMBER( kbd_acia_int ); DECLARE_WRITE_LINE_MEMBER( cmi_acia_int ); @@ -82,6 +169,8 @@ private: output_finder<12> m_digit; emu_timer *m_cmi10_scnd_timer; + emu_timer *m_velocity_timers[KEY_COUNT]; + bool m_key_held[KEY_COUNT]; int m_kbd_acia_irq; int m_cmi_acia_irq; -- cgit v1.2.3