mirror of
https://github.com/holub/mame
synced 2025-04-21 07:52:35 +03:00
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.
This commit is contained in:
parent
8c5e73a6fa
commit
9cdce3047e
@ -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:
|
||||
|
@ -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")
|
||||
|
@ -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<uint8_t>();
|
||||
m_tx_active = false;
|
||||
|
||||
transmit_register_reset();
|
||||
}
|
||||
|
@ -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<uint8_t> m_rx_fifo;
|
||||
std::queue<uint8_t> 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
|
||||
|
@ -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<hc55516_device> m_cvsd;
|
||||
required_device<mc6845_device> m_crtc;
|
||||
required_device<ram_device> m_ram;
|
||||
optional_device<filter_biquad_device> m_cvsd_filter;
|
||||
optional_device<filter_biquad_device> m_cvsd_filter2;
|
||||
required_device<victor_9000_keyboard_device> m_kb;
|
||||
required_device<victor_9000_fdc_device> m_fdc;
|
||||
required_device<centronics_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 )
|
||||
|
Loading…
Reference in New Issue
Block a user