From 9cdce3047e51b92002f6ea33bb2e1550b2ab5293 Mon Sep 17 00:00:00 2001 From: donohoe00 <205851956+donohoe00@users.noreply.github.com> Date: Fri, 11 Apr 2025 18:48:57 -0400 Subject: [PATCH] act/victor9k.cpp: Get audio working on Victor 9000 (victor9k) (#13549) * 6522via: Don't generate a signal on PB7 when the timer 1 latch is programmed with 0. On the Victor 9000, the clock for the audio codec is generated by a via6522. PB7 is connected to the codec's clock input. Non-speech sounds (e.g. beeps, musical notes) are produced by outputting a cyclical waveform from the codec, with the pitch determined by the frequency of the codec clock. Software running on the Victor 9000 has been observed to attempt to silence the audio by writing 0 to the T1 timer latch (not by turning off continuous mode or PB7 output). With the emulated via6522, this resulted in a high-frequency clock signal being output on PB7, causing a high-pitched squeal whenever notes are not being played. From this observed behavior we could infer that the original 6522 HW does not output a signal on PB7 when the latch value is 0, and that the Victor 9000 software was relying on this behaviour to silence the audio output (one would have to assume that the real hardware didn't produce a squeal). * mc6852: fix various transmit-related issues which were preventing victor9k Audio output from working. The expected behavior of mc6852 is to write the data received in the FIFO register serially via tx_data_callback(). However, this was not implemented, and the only way data in the transmit FIFO could be removed and transmitted was by calling get_tx_byte(), and to then serially transmit the data by some external mechanism. Only m68sfdc.cpp calls get_tx_byte(), so it's hard to see how any other device using the mc6852 would have been able to transmit data. Software running on victor9k attempting to play audio would hang, since it would block waiting for the TX FIFO to empty. With these changes, Victor 9000 audio playback works as expected, with the data getting sent serially to the Audio codec. In order to avoid breaking m68sfdc, a new API call is added to allow data to be sent the "old" way. m68sfdc now calls set_tx_pull_mode(true), to get the previous behavior. As I understand it, other devices using mc6852 must be broken, and would need to be revisited. * victor9k: complete Audio support, adding a low-pass filter after the HC-55516 codec. Mark victor9k Audio as working. --- src/devices/machine/6522via.cpp | 20 +++++++++-- src/devices/machine/m68sfdc.cpp | 1 + src/devices/machine/mc6852.cpp | 60 +++++++++++++++++++++++++++++---- src/devices/machine/mc6852.h | 12 ++++++- src/mame/act/victor9k.cpp | 23 ++++++++++--- 5 files changed, 100 insertions(+), 16 deletions(-) diff --git a/src/devices/machine/6522via.cpp b/src/devices/machine/6522via.cpp index 1b1d0ea0766..d4a2de29f5c 100644 --- a/src/devices/machine/6522via.cpp +++ b/src/devices/machine/6522via.cpp @@ -535,7 +535,14 @@ TIMER_CALLBACK_MEMBER(via6522_device::t1_tick) if (T1_CONTINUOUS (m_acr)) { m_t1_pb7 = !m_t1_pb7; - m_t1->adjust(clocks_to_attotime(TIMER1_VALUE + IFR_DELAY)); + if (TIMER1_VALUE > 0) + { + m_t1->adjust(clocks_to_attotime(TIMER1_VALUE + IFR_DELAY)); + } + else + { + m_t1_active = 0; + } } else { @@ -934,8 +941,15 @@ void via6522_device::write(offs_t offset, u8 data) output_pb(); } - m_t1->adjust(clocks_to_attotime(TIMER1_VALUE + IFR_DELAY)); - m_t1_active = 1; + if (TIMER1_VALUE > 0) + { + m_t1->adjust(clocks_to_attotime(TIMER1_VALUE + IFR_DELAY)); + m_t1_active = 1; + } + else + { + m_t1_active = 0; + } break; case VIA_T2CL: diff --git a/src/devices/machine/m68sfdc.cpp b/src/devices/machine/m68sfdc.cpp index f235f25bfd5..ced33a54510 100644 --- a/src/devices/machine/m68sfdc.cpp +++ b/src/devices/machine/m68sfdc.cpp @@ -842,6 +842,7 @@ void m68sfdc_device::device_add_mconfig(machine_config &config) m_pia->irqb_handler().set(FUNC(m68sfdc_device::handle_irq)); MC6852(config, m_ssda, 0); + m_ssda->set_tx_pull_mode(true); } DEFINE_DEVICE_TYPE(M68SFDC, m68sfdc_device, "m68sfdc", "M68SFDC") diff --git a/src/devices/machine/mc6852.cpp b/src/devices/machine/mc6852.cpp index af74f26516c..e54d5d3d4bf 100644 --- a/src/devices/machine/mc6852.cpp +++ b/src/devices/machine/mc6852.cpp @@ -51,6 +51,8 @@ mc6852_device::mc6852_device(const machine_config &mconfig, const char *tag, dev m_write_irq(*this), m_write_sm_dtr(*this), m_write_tuf(*this), + m_tx_pull_mode(false), + m_tx_active(false), m_rx_clock(0), m_tx_clock(0), m_cts(1), @@ -84,6 +86,8 @@ void mc6852_device::device_start() save_item(NAME(m_sm_dtr)); save_item(NAME(m_tuf)); save_item(NAME(m_in_sync)); + save_item(NAME(m_tx_active)); + save_item(NAME(m_tx_pull_mode)); } @@ -125,7 +129,39 @@ void mc6852_device::tra_callback() void mc6852_device::tra_complete() { - // TODO + int trigger = (m_cr[1] & C2_1_2_BYTE) ? 1 : 2; + int available = 3 - m_tx_fifo.size(); + uint8_t byte_to_send; + + if (available < 3) + { + // FIFO not empty - send the next byte. + byte_to_send = m_tx_fifo.front(); + m_tx_fifo.pop(); + available++; + } + else + { + // TX underflow + if (m_cr[1] & C2_TX_SYNC) + { + m_status |= S_TUF; + byte_to_send = m_scr; // Send Sync Code + + // TODO assert TUF pin for "approximately one Tx CLK high period" + } + else + { + byte_to_send = 0xff; // Send a "Mark" + } + } + + transmit_register_setup(byte_to_send); + + if (available >= trigger) + { + m_status |= S_TDRA; + } } //------------------------------------------------- @@ -234,7 +270,7 @@ uint8_t mc6852_device::read(offs_t offset) // TODO this might not be quite right, the datasheet // states that the RX overrun flag is cleared by // reading the status, and the RX data fifo? - m_status &= S_RX_OVRN; + m_status &= ~S_RX_OVRN; } } @@ -311,9 +347,9 @@ void mc6852_device::write(offs_t offset, uint8_t data) int data_bit_count = 0; parity_t parity = PARITY_NONE; - stop_bits_t stop_bits = STOP_BITS_1; + stop_bits_t stop_bits = STOP_BITS_0; - switch (data & C2_WS_MASK) + switch ((data & C2_WS_MASK) >> C2_WS_SHIFT) { case 0: data_bit_count = 6; parity = PARITY_EVEN; break; case 1: data_bit_count = 6; parity = PARITY_ODD; break; @@ -325,7 +361,7 @@ void mc6852_device::write(offs_t offset, uint8_t data) case 7: data_bit_count = 8; parity = PARITY_ODD; break; } - set_data_frame(1, data_bit_count, parity, stop_bits); + set_data_frame(0, data_bit_count, parity, stop_bits); // The fifo trigger levels may have changed, so update // the status bits. @@ -374,8 +410,17 @@ void mc6852_device::write(offs_t offset, uint8_t data) if (available > 0) { LOG("MC6852 Transmit FIFO %02x\n", data); - m_tx_fifo.push(data); - available--; + if (!m_tx_pull_mode && !m_tx_active) { + // transfer is idle: this emulates moving the first byte + // into the shift register, and kicking off transmission. + // tra_complete() will be called when the byte has been + // sent. + m_tx_active = true; + transmit_register_setup(data); + } else { + m_tx_fifo.push(data); + available--; + } } else { @@ -426,6 +471,7 @@ void mc6852_device::write(offs_t offset, uint8_t data) m_status &= ~(S_TUF | S_CTS); m_status |= S_TDRA; m_tx_fifo = std::queue(); + m_tx_active = false; transmit_register_reset(); } diff --git a/src/devices/machine/mc6852.h b/src/devices/machine/mc6852.h index 3092ba2374c..c7862be4d1e 100644 --- a/src/devices/machine/mc6852.h +++ b/src/devices/machine/mc6852.h @@ -47,6 +47,8 @@ public: void set_rx_clock(int clock) { m_rx_clock = clock; } void set_tx_clock(int clock) { m_tx_clock = clock; } + void set_tx_pull_mode(bool tx_pull_mode) { m_tx_pull_mode = tx_pull_mode; } + auto tx_data_callback() { return m_write_tx_data.bind(); } auto irq_callback() { return m_write_irq.bind(); } auto sm_dtr_callback() { return m_write_sm_dtr.bind(); } @@ -120,7 +122,8 @@ private: C2_1_2_BYTE = 0x04, C2_PC_MASK = 0x03, C2_PC2 = 0x02, - C2_PC1 = 0x01 + C2_PC1 = 0x01, + C2_WS_SHIFT = 3 }; enum @@ -147,6 +150,13 @@ private: std::queue m_rx_fifo; std::queue m_tx_fifo; + // If m_tx_pull_mode is true, get_tx_byte() must be called to retrieve + // the next byte to transmit, and the actual transmission must be + // carried out by some external mechanism. + bool m_tx_pull_mode; + + bool m_tx_active; + int m_rx_clock; int m_tx_clock; int m_cts; // clear to send diff --git a/src/mame/act/victor9k.cpp b/src/mame/act/victor9k.cpp index 235e70c46db..ed6e97f86d1 100644 --- a/src/mame/act/victor9k.cpp +++ b/src/mame/act/victor9k.cpp @@ -34,10 +34,12 @@ #include "machine/pit8253.h" #include "machine/pic8259.h" #include "machine/ram.h" +#include "machine/rescap.h" #include "victor9k_kb.h" #include "victor9k_fdc.h" #include "machine/z80sio.h" #include "sound/hc55516.h" +#include "sound/flt_biquad.h" #include "video/mc6845.h" #include "emupal.h" #include "screen.h" @@ -104,6 +106,8 @@ public: m_cvsd(*this, HC55516_TAG), m_crtc(*this, HD46505S_TAG), m_ram(*this, RAM_TAG), + m_cvsd_filter(*this, "cvsd_filter"), + m_cvsd_filter2(*this, "cvsd_filter2"), m_kb(*this, KB_TAG), m_fdc(*this, "fdc"), m_centronics(*this, "centronics"), @@ -138,6 +142,8 @@ private: required_device m_cvsd; required_device m_crtc; required_device m_ram; + optional_device m_cvsd_filter; + optional_device m_cvsd_filter2; required_device m_kb; required_device m_fdc; required_device m_centronics; @@ -391,7 +397,12 @@ void victor9k_state::ssda_sm_dtr_w(int state) { m_ssda->cts_w(state); m_ssda->dcd_w(!state); - //m_cvsd->enc_dec_w(!state); + + /* ___ + * We're supposed to set the ENC/DEC input of the HC55516 to !state, + * but only playback/decode is currently supported, and that input + * is not implemenented. + */ } @@ -733,10 +744,12 @@ void victor9k_state::victor9k(machine_config &config) m_crtc->set_begin_update_callback(FUNC(victor9k_state::crtc_begin_update)); // sound hardware + FILTER_BIQUAD(config, m_cvsd_filter2).opamp_mfb_lowpass_setup(RES_K(27), RES_K(15), RES_K(27), CAP_P(4700), CAP_P(1200)); + FILTER_BIQUAD(config, m_cvsd_filter).opamp_mfb_lowpass_setup(RES_K(43), RES_K(36), RES_K(180), CAP_P(1800), CAP_P(180)); + HC55516(config, m_cvsd, 0).add_route(ALL_OUTPUTS, m_cvsd_filter, 1.0); + m_cvsd_filter->add_route(ALL_OUTPUTS, m_cvsd_filter2, 1.0); + m_cvsd_filter2->add_route(ALL_OUTPUTS, "mono", 0.25); SPEAKER(config, "mono").front_center(); - HC55516(config, m_cvsd, 0); - //MCFG_HC55516_DIG_OUT_CB(WRITELINE(MC6852_TAG, mc6852_device, rx_w)) - m_cvsd->add_route(ALL_OUTPUTS, "mono", 0.25); // devices IEEE488(config, m_ieee488, 0); @@ -853,4 +866,4 @@ ROM_END //************************************************************************** // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -COMP( 1982, victor9k, 0, 0, victor9k, victor9k, victor9k_state, empty_init, "Victor Business Products", "Victor 9000", MACHINE_IMPERFECT_COLORS | MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) +COMP( 1982, victor9k, 0, 0, victor9k, victor9k, victor9k_state, empty_init, "Victor Business Products", "Victor 9000", MACHINE_IMPERFECT_COLORS | MACHINE_SUPPORTS_SAVE )