// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
atariscom.cpp
Atari sound communications device.
***************************************************************************/
#include "emu.h"
#include "atariscom.h"
#include "cpu/m6502/m6502.h"
/***************************************************************************
CONSTANTS
***************************************************************************/
#define SOUND_TIMER_RATE attotime::from_usec(5)
#define SOUND_TIMER_BOOST attotime::from_usec(1000)
//**************************************************************************
// SOUND COMMUNICATIONS DEVICE
//**************************************************************************
// device type definition
DEFINE_DEVICE_TYPE(ATARI_SOUND_COMM, atari_sound_comm_device, "atariscom", "Atari Sound Communications")
//-------------------------------------------------
// atari_sound_comm_device - constructor
//-------------------------------------------------
atari_sound_comm_device::atari_sound_comm_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, ATARI_SOUND_COMM, tag, owner, clock)
, m_main_int_cb(*this)
, m_sound_cpu(*this, finder_base::DUMMY_TAG)
, m_main_to_sound_ready(false)
, m_sound_to_main_ready(false)
, m_main_to_sound_data(0)
, m_sound_to_main_data(0)
{
}
//-------------------------------------------------
// device_start: Start up the device
//-------------------------------------------------
void atari_sound_comm_device::device_start()
{
// resolve callbacks
m_main_int_cb.resolve_safe();
// register for save states
save_item(NAME(m_main_to_sound_ready));
save_item(NAME(m_sound_to_main_ready));
save_item(NAME(m_main_to_sound_data));
save_item(NAME(m_sound_to_main_data));
}
//-------------------------------------------------
// device_reset: Handle a device reset by
// clearing the interrupt lines and states
//-------------------------------------------------
void atari_sound_comm_device::device_reset()
{
// reset the sound I/O states
m_main_to_sound_data = m_sound_to_main_data = 0;
m_main_to_sound_ready = m_sound_to_main_ready = false;
}
//-------------------------------------------------
// device_timer: Handle device-specific timer
// calbacks
//-------------------------------------------------
void atari_sound_comm_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch (id)
{
case TID_SOUND_RESET:
delayed_sound_reset(param);
break;
case TID_SOUND_WRITE:
delayed_sound_write(param);
break;
case TID_6502_WRITE:
delayed_6502_write(param);
break;
}
}
//-------------------------------------------------
// sound_reset_w: Write handler which resets the
// sound CPU in response.
//-------------------------------------------------
void atari_sound_comm_device::sound_reset_w(u16 data)
{
synchronize(TID_SOUND_RESET);
}
//-------------------------------------------------
// main_command_w: Handles communication from the main CPU
// to the sound CPU. Two versions are provided, one with the
// data byte in the low 8 bits, and one with the data byte in
// the upper 8 bits.
//-------------------------------------------------
void atari_sound_comm_device::main_command_w(u8 data)
{
synchronize(TID_SOUND_WRITE, data);
}
//-------------------------------------------------
// main_response_r: Handles reading data communicated from the
// sound CPU to the main CPU. Two versions are provided, one
// with the data byte in the low 8 bits, and one with the data
// byte in the upper 8 bits.
//-------------------------------------------------
u8 atari_sound_comm_device::main_response_r()
{
if (!machine().side_effects_disabled())
{
m_sound_to_main_ready = false;
m_main_int_cb(CLEAR_LINE);
}
return m_sound_to_main_data;
}
//-------------------------------------------------
// sound_response_w: Handles communication from the
// sound CPU to the main CPU.
//-------------------------------------------------
void atari_sound_comm_device::sound_response_w(u8 data)
{
synchronize(TID_6502_WRITE, data);
}
//-------------------------------------------------
// sound_command_r: Handles reading data
// communicated from the main CPU to the sound
// CPU.
//-------------------------------------------------
u8 atari_sound_comm_device::sound_command_r()
{
if (!machine().side_effects_disabled())
{
m_main_to_sound_ready = false;
m_sound_cpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
}
return m_main_to_sound_data;
}
//-------------------------------------------------
// delayed_sound_reset: Synchronizes the sound
// reset command between the two CPUs.
//-------------------------------------------------
void atari_sound_comm_device::delayed_sound_reset(int param)
{
// unhalt and reset the sound CPU
if (param == 0)
{
m_sound_cpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
m_sound_cpu->pulse_input_line(INPUT_LINE_RESET, attotime::zero);
}
// reset the sound write state
m_sound_to_main_ready = false;
m_main_int_cb(CLEAR_LINE);
// allocate a high frequency timer until a response is generated
// the main CPU is *very* sensistive to the timing of the response
machine().scheduler().boost_interleave(SOUND_TIMER_RATE, SOUND_TIMER_BOOST);
}
//-------------------------------------------------
// delayed_sound_write: Synchronizes a data write
// from the main CPU to the sound CPU.
//-------------------------------------------------
void atari_sound_comm_device::delayed_sound_write(int data)
{
// warn if we missed something
if (m_main_to_sound_ready)
logerror("Missed command from 680x0\n");
// set up the states and signal an NMI to the sound CPU
m_main_to_sound_data = data;
m_main_to_sound_ready = true;
m_sound_cpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
// allocate a high frequency timer until a response is generated
// the main CPU is *very* sensistive to the timing of the response
machine().scheduler().boost_interleave(SOUND_TIMER_RATE, SOUND_TIMER_BOOST);
}
//-------------------------------------------------
// delayed_6502_write: Synchronizes a data write
// from the sound CPU to the main CPU.
//-------------------------------------------------
void atari_sound_comm_device::delayed_6502_write(int data)
{
// warn if we missed something
if (m_sound_to_main_ready)
logerror("Missed result from 6502\n");
// set up the states and signal the sound interrupt to the main CPU
m_sound_to_main_data = data;
m_sound_to_main_ready = true;
m_main_int_cb(ASSERT_LINE);
}