summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/am9517a.cpp
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
committer Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
commit7c19aac60e12d6f5ea301bdb34d7826a01e0b06f (patch)
treef310d86aa2c6bfc19d115307dedde4eb0cd52dad /src/devices/machine/am9517a.cpp
parenta57b46ae933badd7441ce1644711dbb851e2b504 (diff)
Rename *.c -> *.cpp in our source (nw)
Diffstat (limited to 'src/devices/machine/am9517a.cpp')
-rw-r--r--src/devices/machine/am9517a.cpp1279
1 files changed, 1279 insertions, 0 deletions
diff --git a/src/devices/machine/am9517a.cpp b/src/devices/machine/am9517a.cpp
new file mode 100644
index 00000000000..469da3d167f
--- /dev/null
+++ b/src/devices/machine/am9517a.cpp
@@ -0,0 +1,1279 @@
+// license:BSD-3-Clause
+// copyright-holders:Curt Coder
+/***************************************************************************
+
+ AMD AM9517A
+ Intel 8237A
+ NEC uPD71037
+
+ NEC uPD71071 (extended version of above)
+
+ a variant is used in the V53 CPU which offers subsets of both the
+ uPD71071 and uPD71037 functionality depending on a mode bit.
+
+ Multimode DMA Controller emulation
+
+***************************************************************************/
+
+/*
+
+ TODO:
+
+ - external EOP
+
+*/
+
+/*
+
+ When the V53 operates in uPD71071 compatible mode there are the following
+ differences from a real uPD71071
+
+ V53 Real uPD71071
+ Software Reqs No Yes
+ Memory-to-Memory DMA No Yes
+ DMARQ active level High programmable
+ DMAAK active level Low programmable
+ Bus Cycle 4 4 or 3
+
+ we don't currently handle the differences
+
+*/
+
+#include "am9517a.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type AM9517A = &device_creator<am9517a_device>;
+const device_type V53_DMAU = &device_creator<upd71071_v53_device>;
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+enum
+{
+ REGISTER_ADDRESS = 0,
+ REGISTER_WORD_COUNT,
+ REGISTER_STATUS = 8,
+ REGISTER_COMMAND = REGISTER_STATUS,
+ REGISTER_REQUEST,
+ REGISTER_SINGLE_MASK,
+ REGISTER_MODE,
+ REGISTER_BYTE_POINTER,
+ REGISTER_TEMPORARY,
+ REGISTER_MASTER_CLEAR = REGISTER_TEMPORARY,
+ REGISTER_CLEAR_MASK,
+ REGISTER_MASK
+};
+
+
+#define COMMAND_MEM_TO_MEM BIT(m_command, 0)
+#define COMMAND_CH0_ADDRESS_HOLD BIT(m_command, 1)
+#define COMMAND_DISABLE BIT(m_command, 2)
+#define COMMAND_COMPRESSED_TIMING BIT(m_command, 3)
+#define COMMAND_ROTATING_PRIORITY BIT(m_command, 4)
+#define COMMAND_EXTENDED_WRITE BIT(m_command, 5)
+#define COMMAND_DREQ_ACTIVE_LOW BIT(m_command, 6)
+#define COMMAND_DACK_ACTIVE_HIGH BIT(m_command, 7)
+
+
+#define MODE_TRANSFER_MASK (m_channel[m_current_channel].m_mode & 0x0c)
+#define MODE_TRANSFER_VERIFY 0x00
+#define MODE_TRANSFER_WRITE 0x04
+#define MODE_TRANSFER_READ 0x08
+#define MODE_TRANSFER_ILLEGAL 0x0c
+#define MODE_AUTOINITIALIZE BIT(m_channel[m_current_channel].m_mode, 4)
+#define MODE_ADDRESS_DECREMENT BIT(m_channel[m_current_channel].m_mode, 5)
+#define MODE_MASK (m_channel[m_current_channel].m_mode & 0xc0)
+#define MODE_DEMAND 0x00
+#define MODE_SINGLE 0x40
+#define MODE_BLOCK 0x80
+#define MODE_CASCADE 0xc0
+
+
+enum
+{
+ STATE_SI,
+ STATE_S0,
+ STATE_SC,
+ STATE_S1,
+ STATE_S2,
+ STATE_S3,
+ STATE_SW,
+ STATE_S4,
+ STATE_S11,
+ STATE_S12,
+ STATE_S13,
+ STATE_S14,
+ STATE_S21,
+ STATE_S22,
+ STATE_S23,
+ STATE_S24
+};
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// dma_request -
+//-------------------------------------------------
+
+inline void am9517a_device::dma_request(int channel, int state)
+{
+ if (LOG) logerror("AM9517A '%s' Channel %u DMA Request: %u\n", tag(), channel, state);
+
+ if (state ^ COMMAND_DREQ_ACTIVE_LOW)
+ {
+ m_status |= (1 << (channel + 4));
+ }
+ else
+ {
+ m_status &= ~(1 << (channel + 4));
+ }
+ trigger(1);
+}
+
+
+//-------------------------------------------------
+// is_request_active -
+//-------------------------------------------------
+
+inline bool am9517a_device::is_request_active(int channel)
+{
+ return (BIT(m_status, channel + 4) & !BIT(m_mask, channel)) ? true : false;
+}
+
+
+//-------------------------------------------------
+// is_software_request_active -
+//-------------------------------------------------
+
+inline bool am9517a_device::is_software_request_active(int channel)
+{
+ return BIT(m_request, channel) && ((m_channel[channel].m_mode & 0xc0) == MODE_BLOCK);
+}
+
+
+//-------------------------------------------------
+// set_hreq
+//-------------------------------------------------
+
+inline void am9517a_device::set_hreq(int state)
+{
+ if (m_hreq != state)
+ {
+ m_out_hreq_cb(state);
+
+ m_hreq = state;
+ }
+}
+
+
+//-------------------------------------------------
+// set_dack -
+//-------------------------------------------------
+
+inline void am9517a_device::set_dack()
+{
+ for (int channel = 0; channel < 4; channel++)
+ {
+ if (channel == 0)
+ {
+ if ((channel == m_current_channel) && !COMMAND_MEM_TO_MEM)
+ {
+ m_out_dack_0_cb(COMMAND_DACK_ACTIVE_HIGH);
+ }
+ else
+ {
+ m_out_dack_0_cb(!COMMAND_DACK_ACTIVE_HIGH);
+ }
+ }
+ else if (channel == 1)
+ {
+ if ((channel == m_current_channel) && !COMMAND_MEM_TO_MEM)
+ {
+ m_out_dack_1_cb(COMMAND_DACK_ACTIVE_HIGH);
+ }
+ else
+ {
+ m_out_dack_1_cb(!COMMAND_DACK_ACTIVE_HIGH);
+ }
+ }
+ else if (channel == 2)
+ {
+ if ((channel == m_current_channel) && !COMMAND_MEM_TO_MEM)
+ {
+ m_out_dack_2_cb(COMMAND_DACK_ACTIVE_HIGH);
+ }
+ else
+ {
+ m_out_dack_2_cb(!COMMAND_DACK_ACTIVE_HIGH);
+ }
+ }
+ else if (channel == 3)
+ {
+ if ((channel == m_current_channel) && !COMMAND_MEM_TO_MEM)
+ {
+ m_out_dack_3_cb(COMMAND_DACK_ACTIVE_HIGH);
+ }
+ else
+ {
+ m_out_dack_3_cb(!COMMAND_DACK_ACTIVE_HIGH);
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// set_eop -
+//-------------------------------------------------
+
+inline void am9517a_device::set_eop(int state)
+{
+ if (m_eop != state)
+ {
+ m_out_eop_cb(state);
+
+ m_eop = state;
+ }
+}
+
+
+//-------------------------------------------------
+// dma_read -
+//-------------------------------------------------
+
+inline int am9517a_device::get_state1(bool msb_changed)
+{
+ if (COMMAND_MEM_TO_MEM)
+ {
+ return msb_changed ? STATE_S11 : STATE_S12;
+ }
+ else
+ {
+ return msb_changed ? STATE_S1 : STATE_S2;
+ }
+}
+
+
+//-------------------------------------------------
+// dma_read -
+//-------------------------------------------------
+
+inline void am9517a_device::dma_read()
+{
+ offs_t offset = m_channel[m_current_channel].m_address;
+
+ switch (MODE_TRANSFER_MASK)
+ {
+ case MODE_TRANSFER_VERIFY:
+ case MODE_TRANSFER_WRITE:
+ switch(m_current_channel)
+ {
+ case 0:
+ m_temp = m_in_ior_0_cb(offset);
+ break;
+ case 1:
+ m_temp = m_in_ior_1_cb(offset);
+ break;
+ case 2:
+ m_temp = m_in_ior_2_cb(offset);
+ break;
+ case 3:
+ m_temp = m_in_ior_3_cb(offset);
+ break;
+ }
+ break;
+
+ case MODE_TRANSFER_READ:
+ m_temp = m_in_memr_cb(offset);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// dma_write -
+//-------------------------------------------------
+
+inline void am9517a_device::dma_write()
+{
+ offs_t offset = m_channel[m_current_channel].m_address;
+
+ switch (MODE_TRANSFER_MASK)
+ {
+ case MODE_TRANSFER_VERIFY: {
+ UINT8 v1 = m_in_memr_cb(offset);
+ if(0 && m_temp != v1)
+ logerror("%s: verify error %02x vs. %02x\n", tag(), m_temp, v1);
+ break;
+ }
+
+ case MODE_TRANSFER_WRITE:
+ m_out_memw_cb(offset, m_temp);
+ break;
+
+ case MODE_TRANSFER_READ:
+ switch(m_current_channel)
+ {
+ case 0:
+ m_out_iow_0_cb(offset, m_temp);
+ break;
+ case 1:
+ m_out_iow_1_cb(offset, m_temp);
+ break;
+ case 2:
+ m_out_iow_2_cb(offset, m_temp);
+ break;
+ case 3:
+ m_out_iow_3_cb(offset, m_temp);
+ break;
+ }
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// dma_advance -
+//-------------------------------------------------
+
+inline void am9517a_device::dma_advance()
+{
+ bool msb_changed = false;
+
+ m_channel[m_current_channel].m_count--;
+
+ if (m_current_channel || !COMMAND_MEM_TO_MEM || !COMMAND_CH0_ADDRESS_HOLD)
+ {
+ if (MODE_ADDRESS_DECREMENT)
+ {
+ m_channel[m_current_channel].m_address--;
+ m_channel[m_current_channel].m_address &= m_address_mask;
+
+ if ((m_channel[m_current_channel].m_address & 0xff) == 0xff)
+ {
+ msb_changed = true;
+ }
+ }
+ else
+ {
+ m_channel[m_current_channel].m_address++;
+ m_channel[m_current_channel].m_address &= m_address_mask;
+
+ if ((m_channel[m_current_channel].m_address & 0xff) == 0x00)
+ {
+ msb_changed = true;
+ }
+ }
+ }
+
+ if (m_channel[m_current_channel].m_count == 0xffff)
+ {
+ end_of_process();
+ }
+ else
+ {
+ switch (MODE_MASK)
+ {
+ case MODE_DEMAND:
+ if (!is_request_active(m_current_channel))
+ {
+ set_hreq(0);
+ set_dack();
+ m_state = STATE_SI;
+ }
+ else
+ {
+ m_state = get_state1(msb_changed);
+ }
+ break;
+
+ case MODE_SINGLE:
+ set_hreq(0);
+ set_dack();
+ m_state = STATE_SI;
+ break;
+
+ case MODE_BLOCK:
+ m_state = get_state1(msb_changed);
+ break;
+
+ case MODE_CASCADE:
+ break;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// end_of_process -
+//-------------------------------------------------
+
+inline void am9517a_device::end_of_process()
+{
+ // terminal count
+ if (COMMAND_MEM_TO_MEM)
+ {
+ m_status |= 1 << 0;
+ m_status |= 1 << 1;
+ m_request &= ~(1 << 0);
+ m_request &= ~(1 << 1);
+ }
+ else
+ {
+ m_status |= 1 << m_current_channel;
+ m_request &= ~(1 << m_current_channel);
+ }
+
+ if (MODE_AUTOINITIALIZE)
+ {
+ // autoinitialize
+ m_channel[m_current_channel].m_address = m_channel[m_current_channel].m_base_address;
+ m_channel[m_current_channel].m_count = m_channel[m_current_channel].m_base_count;
+ }
+ else
+ {
+ // mask out channel
+ m_mask |= 1 << m_current_channel;
+ }
+
+ // signal end of process
+ set_eop(ASSERT_LINE);
+ set_hreq(0);
+
+ m_current_channel = -1;
+ set_dack();
+
+ m_state = STATE_SI;
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// am9517a_device - constructor
+//-------------------------------------------------
+
+
+am9517a_device::am9517a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname)
+ : device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__),
+ device_execute_interface(mconfig, *this),
+ m_icount(0),
+ m_hack(0),
+ m_ready(1),
+ m_command(0),
+ m_out_hreq_cb(*this),
+ m_out_eop_cb(*this),
+ m_in_memr_cb(*this),
+ m_out_memw_cb(*this),
+ m_in_ior_0_cb(*this),
+ m_in_ior_1_cb(*this),
+ m_in_ior_2_cb(*this),
+ m_in_ior_3_cb(*this),
+ m_out_iow_0_cb(*this),
+ m_out_iow_1_cb(*this),
+ m_out_iow_2_cb(*this),
+ m_out_iow_3_cb(*this),
+ m_out_dack_0_cb(*this),
+ m_out_dack_1_cb(*this),
+ m_out_dack_2_cb(*this),
+ m_out_dack_3_cb(*this)
+{
+}
+
+
+am9517a_device::am9517a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, AM9517A, "AM9517A", tag, owner, clock, "am9517a", __FILE__),
+ device_execute_interface(mconfig, *this),
+ m_icount(0),
+ m_hack(0),
+ m_ready(1),
+ m_command(0),
+ m_out_hreq_cb(*this),
+ m_out_eop_cb(*this),
+ m_in_memr_cb(*this),
+ m_out_memw_cb(*this),
+ m_in_ior_0_cb(*this),
+ m_in_ior_1_cb(*this),
+ m_in_ior_2_cb(*this),
+ m_in_ior_3_cb(*this),
+ m_out_iow_0_cb(*this),
+ m_out_iow_1_cb(*this),
+ m_out_iow_2_cb(*this),
+ m_out_iow_3_cb(*this),
+ m_out_dack_0_cb(*this),
+ m_out_dack_1_cb(*this),
+ m_out_dack_2_cb(*this),
+ m_out_dack_3_cb(*this)
+
+{
+}
+
+upd71071_v53_device::upd71071_v53_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : am9517a_device(mconfig, V53_DMAU, "V53 DMAU", tag, owner, clock, "v53_dmau")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void am9517a_device::device_start()
+{
+ // set our instruction counter
+ m_icountptr = &m_icount;
+
+ // resolve callbacks
+ m_out_hreq_cb.resolve_safe();
+ m_out_eop_cb.resolve_safe();
+ m_in_memr_cb.resolve_safe(0);
+ m_out_memw_cb.resolve_safe();
+ m_in_ior_0_cb.resolve_safe(0);
+ m_in_ior_1_cb.resolve_safe(0);
+ m_in_ior_2_cb.resolve_safe(0);
+ m_in_ior_3_cb.resolve_safe(0);
+ m_out_iow_0_cb.resolve_safe();
+ m_out_iow_1_cb.resolve_safe();
+ m_out_iow_2_cb.resolve_safe();
+ m_out_iow_3_cb.resolve_safe();
+ m_out_dack_0_cb.resolve_safe();
+ m_out_dack_1_cb.resolve_safe();
+ m_out_dack_2_cb.resolve_safe();
+ m_out_dack_3_cb.resolve_safe();
+
+ for (int i = 0; i < 4; i++)
+ {
+ m_channel[i].m_address = 0;
+ m_channel[i].m_count = 0;
+ m_channel[i].m_base_address = 0;
+ m_channel[i].m_base_count = 0;
+ m_channel[i].m_mode = 0;
+ }
+
+ // state saving
+ save_item(NAME(m_msb));
+ save_item(NAME(m_hreq));
+ save_item(NAME(m_hack));
+ save_item(NAME(m_ready));
+ save_item(NAME(m_eop));
+ save_item(NAME(m_state));
+ save_item(NAME(m_current_channel));
+ save_item(NAME(m_last_channel));
+ save_item(NAME(m_command));
+ save_item(NAME(m_mask));
+ save_item(NAME(m_status));
+ save_item(NAME(m_temp));
+ save_item(NAME(m_request));
+
+ for (int i = 0; i < 4; i++)
+ {
+ save_item(NAME(m_channel[i].m_address), i);
+ save_item(NAME(m_channel[i].m_count), i);
+ save_item(NAME(m_channel[i].m_base_address), i);
+ save_item(NAME(m_channel[i].m_base_count), i);
+ save_item(NAME(m_channel[i].m_mode), i);
+ }
+
+ m_address_mask = 0xffff;
+
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void am9517a_device::device_reset()
+{
+ m_state = STATE_SI;
+ m_command = 0;
+ m_status = 0;
+ m_request = 0;
+ m_mask = 0x0f;
+ m_temp = 0;
+ m_msb = 0;
+ m_current_channel = -1;
+ m_last_channel = 3;
+ m_hreq = -1;
+ m_eop = 0;
+
+ set_hreq(0);
+ set_eop(ASSERT_LINE);
+
+ set_dack();
+}
+
+
+//-------------------------------------------------
+// execute_run -
+//-------------------------------------------------
+
+void am9517a_device::execute_run()
+{
+ do
+ {
+ switch (m_state)
+ {
+ case STATE_SI:
+ set_eop(CLEAR_LINE);
+
+ if (!COMMAND_DISABLE)
+ {
+ int priority[] = { 0, 1, 2, 3 };
+
+ if (COMMAND_ROTATING_PRIORITY)
+ {
+ int last_channel = m_last_channel;
+
+ for (int channel = 3; channel >= 0; channel--)
+ {
+ priority[channel] = last_channel;
+ last_channel--;
+ if (last_channel < 0) last_channel = 3;
+ }
+ }
+
+ for (int channel = 0; channel < 4; channel++)
+ {
+ if (is_request_active(priority[channel]) || is_software_request_active(priority[channel]))
+ {
+ m_current_channel = m_last_channel = priority[channel];
+ m_state = STATE_S0;
+ break;
+ }
+ else if (COMMAND_MEM_TO_MEM && BIT(m_request, channel) && ((m_channel[channel].m_mode & 0xc0) == MODE_SINGLE))
+ {
+ m_current_channel = m_last_channel = priority[channel];
+ m_state = STATE_S0;
+ break;
+ }
+ }
+ }
+ if(m_state == STATE_SI)
+ {
+ suspend_until_trigger(1, true);
+ m_icount = 0;
+ }
+ break;
+
+ case STATE_S0:
+ set_hreq(1);
+
+ if (m_hack)
+ {
+ m_state = (MODE_MASK == MODE_CASCADE) ? STATE_SC : get_state1(true);
+ }
+ else
+ {
+ suspend_until_trigger(1, true);
+ m_icount = 0;
+ }
+ break;
+
+ case STATE_SC:
+ if (!is_request_active(m_current_channel))
+ {
+ set_hreq(0);
+ m_current_channel = -1;
+ m_state = STATE_SI;
+ }
+ else
+ {
+ suspend_until_trigger(1, true);
+ m_icount = 0;
+ }
+
+ set_dack();
+ break;
+
+ case STATE_S1:
+ m_state = STATE_S2;
+ break;
+
+ case STATE_S2:
+ set_dack();
+ m_state = COMMAND_COMPRESSED_TIMING ? STATE_S4 : STATE_S3;
+ break;
+
+ case STATE_S3:
+ dma_read();
+
+ if (COMMAND_EXTENDED_WRITE)
+ {
+ dma_write();
+ }
+
+ m_state = m_ready ? STATE_S4 : STATE_SW;
+ break;
+
+ case STATE_SW:
+ m_state = m_ready ? STATE_S4 : STATE_SW;
+ break;
+
+ case STATE_S4:
+ if (COMMAND_COMPRESSED_TIMING)
+ {
+ dma_read();
+ dma_write();
+ }
+ else if (!COMMAND_EXTENDED_WRITE)
+ {
+ dma_write();
+ }
+
+ dma_advance();
+ break;
+
+ case STATE_S11:
+ m_current_channel = 0;
+
+ m_state = STATE_S12;
+ break;
+
+ case STATE_S12:
+ m_state = STATE_S13;
+ break;
+
+ case STATE_S13:
+ m_state = STATE_S14;
+ break;
+
+ case STATE_S14:
+ dma_read();
+
+ m_state = STATE_S21;
+ break;
+
+ case STATE_S21:
+ m_current_channel = 1;
+
+ m_state = STATE_S22;
+ break;
+
+ case STATE_S22:
+ m_state = STATE_S23;
+ break;
+
+ case STATE_S23:
+ m_state = STATE_S24;
+ break;
+
+ case STATE_S24:
+ dma_write();
+ dma_advance();
+
+ m_current_channel = 0;
+ m_channel[m_current_channel].m_count--;
+ if (MODE_ADDRESS_DECREMENT)
+ {
+ m_channel[m_current_channel].m_address--;
+ m_channel[m_current_channel].m_address &= m_address_mask;
+ }
+ else
+ {
+ m_channel[m_current_channel].m_address++;
+ m_channel[m_current_channel].m_address &= m_address_mask;
+ }
+
+ break;
+ }
+
+ m_icount--;
+ } while (m_icount > 0);
+}
+
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ8_MEMBER( am9517a_device::read )
+{
+ UINT8 data = 0;
+
+ if (!BIT(offset, 3))
+ {
+ int channel = (offset >> 1) & 0x03;
+
+ switch (offset & 0x01)
+ {
+ case REGISTER_ADDRESS:
+ if (m_msb)
+ {
+ data = m_channel[channel].m_address >> 8;
+ }
+ else
+ {
+ data = m_channel[channel].m_address & 0xff;
+ }
+ break;
+
+ case REGISTER_WORD_COUNT:
+ if (m_msb)
+ {
+ data = m_channel[channel].m_count >> 8;
+ }
+ else
+ {
+ data = m_channel[channel].m_count & 0xff;
+ }
+ break;
+ }
+
+ m_msb = !m_msb;
+ }
+ else
+ {
+ switch (offset & 0x0f)
+ {
+ case REGISTER_STATUS:
+ data = m_status;
+
+ // clear TC bits
+ m_status &= 0xf0;
+ break;
+
+ case REGISTER_TEMPORARY:
+ data = m_temp;
+ break;
+
+ case REGISTER_MASK:
+ data = m_mask;
+ break;
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE8_MEMBER( am9517a_device::write )
+{
+ if (!BIT(offset, 3))
+ {
+ int channel = (offset >> 1) & 0x03;
+
+ switch (offset & 0x01)
+ {
+ case REGISTER_ADDRESS:
+ if (m_msb)
+ {
+ m_channel[channel].m_base_address = (data << 8) | (m_channel[channel].m_base_address & 0xff);
+ m_channel[channel].m_address = (data << 8) | (m_channel[channel].m_address & 0xff);
+ }
+ else
+ {
+ m_channel[channel].m_base_address = (m_channel[channel].m_base_address & 0xff00) | data;
+ m_channel[channel].m_address = (m_channel[channel].m_address & 0xff00) | data;
+ }
+
+ if (LOG) logerror("AM9517A '%s' Channel %u Base Address: %04x\n", tag(), channel, m_channel[channel].m_base_address);
+ break;
+
+ case REGISTER_WORD_COUNT:
+ if (m_msb)
+ {
+ m_channel[channel].m_base_count = (data << 8) | (m_channel[channel].m_base_count & 0xff);
+ m_channel[channel].m_count = (data << 8) | (m_channel[channel].m_count & 0xff);
+ }
+ else
+ {
+ m_channel[channel].m_base_count = (m_channel[channel].m_base_count & 0xff00) | data;
+ m_channel[channel].m_count = (m_channel[channel].m_count & 0xff00) | data;
+ }
+
+ if (LOG) logerror("AM9517A '%s' Channel %u Base Word Count: %04x\n", tag(), channel, m_channel[channel].m_base_count);
+ break;
+ }
+
+ m_msb = !m_msb;
+ }
+ else
+ {
+ switch (offset & 0x0f)
+ {
+ case REGISTER_COMMAND:
+ m_command = data;
+
+ if (LOG) logerror("AM9517A '%s' Command Register: %02x\n", tag(), m_command);
+ break;
+
+ case REGISTER_REQUEST:
+ {
+ int channel = data & 0x03;
+
+ if (BIT(data, 2))
+ {
+ m_request |= (1 << (channel + 4));
+ if (COMMAND_MEM_TO_MEM)
+ {
+ m_request |= (1 << channel);
+ }
+ }
+ else
+ {
+ m_request &= ~(1 << (channel + 4));
+ }
+
+ if (LOG) logerror("AM9517A '%s' Request Register: %01x\n", tag(), m_request);
+ }
+ break;
+
+ case REGISTER_SINGLE_MASK:
+ {
+ int channel = data & 0x03;
+
+ if (BIT(data, 2))
+ {
+ m_mask |= (1 << channel);
+ }
+ else
+ {
+ m_mask &= ~(1 << channel);
+ }
+
+ if (LOG) logerror("AM9517A '%s' Mask Register: %01x\n", tag(), m_mask);
+ }
+ break;
+
+ case REGISTER_MODE:
+ {
+ int channel = data & 0x03;
+
+ m_channel[channel].m_mode = data & 0xfc;
+
+ // clear terminal count
+ m_status &= ~(1 << channel);
+
+ if (LOG) logerror("AM9517A '%s' Channel %u Mode: %02x\n", tag(), channel, data & 0xfc);
+ }
+ break;
+
+ case REGISTER_BYTE_POINTER:
+ if (LOG) logerror("AM9517A '%s' Clear Byte Pointer Flip-Flop\n", tag());
+
+ m_msb = 0;
+ break;
+
+ case REGISTER_MASTER_CLEAR:
+ if (LOG) logerror("AM9517A '%s' Master Clear\n", tag());
+
+ device_reset();
+ break;
+
+ case REGISTER_CLEAR_MASK:
+ if (LOG) logerror("AM9517A '%s' Clear Mask Register\n", tag());
+
+ m_mask = 0;
+ break;
+
+ case REGISTER_MASK:
+ m_mask = data & 0x0f;
+
+ if (LOG) logerror("AM9517A '%s' Mask Register: %01x\n", tag(), m_mask);
+ break;
+ }
+ }
+ trigger(1);
+}
+
+
+//-------------------------------------------------
+// hack_w - hold acknowledge
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( am9517a_device::hack_w )
+{
+ if (LOG) logerror("AM9517A '%s' Hold Acknowledge: %u\n", tag(), state);
+
+ m_hack = state;
+ trigger(1);
+}
+
+
+//-------------------------------------------------
+// ready_w - ready
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( am9517a_device::ready_w )
+{
+ if (LOG) logerror("AM9517A '%s' Ready: %u\n", tag(), state);
+
+ m_ready = state;
+}
+
+
+//-------------------------------------------------
+// eop_w - end of process
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( am9517a_device::eop_w )
+{
+ if (LOG) logerror("AM9517A '%s' End of Process: %u\n", tag(), state);
+}
+
+
+//-------------------------------------------------
+// dreq0_w - DMA request for channel 0
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( am9517a_device::dreq0_w )
+{
+ dma_request(0, state);
+}
+
+
+//-------------------------------------------------
+// dreq0_w - DMA request for channel 1
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( am9517a_device::dreq1_w )
+{
+ dma_request(1, state);
+}
+
+
+//-------------------------------------------------
+// dreq1_w - DMA request for channel 2
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( am9517a_device::dreq2_w )
+{
+ dma_request(2, state);
+}
+
+
+//-------------------------------------------------
+// dreq3_w - DMA request for channel 3
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( am9517a_device::dreq3_w )
+{
+ dma_request(3, state);
+}
+
+//-------------------------------------------------
+// upd71071 register layouts
+//-------------------------------------------------
+
+void upd71071_v53_device::device_start()
+{
+ am9517a_device::device_start();
+ m_address_mask = 0x00ffffff;
+
+ m_selected_channel = 0;
+ m_base = 0;
+
+ save_item(NAME(m_selected_channel));
+ save_item(NAME(m_base));
+}
+
+void upd71071_v53_device::device_reset()
+{
+ am9517a_device::device_reset();
+
+ m_selected_channel = 0;
+ m_base = 0;
+}
+
+
+READ8_MEMBER(upd71071_v53_device::read)
+{
+ UINT8 ret = 0;
+ int channel = m_selected_channel;
+
+ if (LOG) logerror("DMA: read from register %02x\n",offset);
+
+ switch (offset)
+ {
+ case 0x01: // Channel
+ ret = (1 << m_selected_channel);
+ if (m_base != 0)
+ ret |= 0x10;
+ break;
+ case 0x02: // Count (low)
+ if (m_base != 0)
+ ret = m_channel[channel].m_base_count & 0xff;
+ else
+ ret = m_channel[channel].m_count & 0xff;
+ break;
+ case 0x03: // Count (high)
+ if (m_base != 0)
+ ret = (m_channel[channel].m_base_count >> 8) & 0xff;
+ else
+ ret = (m_channel[channel].m_count >> 8) & 0xff;
+ break;
+ case 0x04: // Address (low)
+ if (m_base != 0)
+ ret = m_channel[channel].m_base_address & 0xff;
+ else
+ ret = m_channel[channel].m_address & 0xff;
+ break;
+ case 0x05: // Address (mid)
+ if (m_base != 0)
+ ret = (m_channel[channel].m_base_address >> 8) & 0xff;
+ else
+ ret = (m_channel[channel].m_address >> 8) & 0xff;
+ break;
+ case 0x06: // Address (high)
+ if (m_base != 0)
+ ret = (m_channel[channel].m_base_address >> 16) & 0xff;
+ else
+ ret = (m_channel[channel].m_address >> 16) & 0xff;
+ break;
+ case 0x07: // Address (highest)
+ if (m_base != 0)
+ ret = (m_channel[channel].m_base_address >> 24) & 0xff;
+ else
+ ret = (m_channel[channel].m_address >> 24) & 0xff;
+ break;
+ case 0x0a: // Mode control
+ ret = (m_channel[channel].m_mode);
+ break;
+
+ case 0x08: // Device control (low)
+ ret = m_command & 0xff;
+ break;
+ case 0x09: // Device control (high) // UPD71071 only?
+ ret = m_command_high & 0xff;
+ break;
+ case 0x0b: // Status
+ ret = m_status;
+ // clear TC bits
+ m_status &= 0xf0;
+ break;
+ case 0x0c: // Temporary (low)
+ ret = m_temp & 0xff;
+ break;
+ case 0x0d: // Temporary (high) // UPD71071 only? (other doesn't do 16-bit?)
+ ret = (m_temp >> 8 ) & 0xff;
+ break;
+ case 0x0e: // Request
+ //ret = m_reg.request;
+ ret = 0; // invalid?
+ break;
+ case 0x0f: // Mask
+ ret = m_mask;
+ break;
+
+ }
+
+ return ret;
+}
+
+WRITE8_MEMBER(upd71071_v53_device::write)
+{
+ int channel = m_selected_channel;
+
+ switch (offset)
+ {
+ case 0x00: // Initialise
+ // TODO: reset (bit 0)
+ //m_buswidth = data & 0x02;
+ //if (data & 0x01)
+ // soft_reset();
+ logerror("DMA: Initialise [%02x]\n", data);
+ break;
+ case 0x01: // Channel
+ m_selected_channel = data & 0x03;
+ m_base = data & 0x04;
+ logerror("DMA: Channel selected [%02x]\n", data);
+ break;
+ case 0x02: // Count (low)
+ m_channel[channel].m_base_count =
+ (m_channel[channel].m_base_count & 0xff00) | data;
+ if (m_base == 0)
+ m_channel[channel].m_count =
+ (m_channel[channel].m_count & 0xff00) | data;
+ logerror("DMA: Channel %i Counter set [%04x]\n", m_selected_channel, m_channel[channel].m_base_count);
+ break;
+ case 0x03: // Count (high)
+ m_channel[channel].m_base_count =
+ (m_channel[channel].m_base_count & 0x00ff) | (data << 8);
+ if (m_base == 0)
+ m_channel[channel].m_count =
+ (m_channel[channel].m_count & 0x00ff) | (data << 8);
+ logerror("DMA: Channel %i Counter set [%04x]\n", m_selected_channel, m_channel[channel].m_base_count);
+ break;
+ case 0x04: // Address (low)
+ m_channel[channel].m_base_address =
+ (m_channel[channel].m_base_address & 0xffffff00) | data;
+ if (m_base == 0)
+ m_channel[channel].m_address =
+ (m_channel[channel].m_address & 0xffffff00) | data;
+ logerror("DMA: Channel %i Address set [%08x]\n", m_selected_channel, m_channel[channel].m_base_address);
+ break;
+ case 0x05: // Address (mid)
+ m_channel[channel].m_base_address =
+ (m_channel[channel].m_base_address & 0xffff00ff) | (data << 8);
+ if (m_base == 0)
+ m_channel[channel].m_address =
+ (m_channel[channel].m_address & 0xffff00ff) | (data << 8);
+ logerror("DMA: Channel %i Address set [%08x]\n", m_selected_channel, m_channel[channel].m_base_address);
+ break;
+ case 0x06: // Address (high)
+ m_channel[channel].m_base_address =
+ (m_channel[channel].m_base_address & 0xff00ffff) | (data << 16);
+ if (m_base == 0)
+ m_channel[channel].m_address =
+ (m_channel[channel].m_address & 0xff00ffff) | (data << 16);
+ logerror("DMA: Channel %i Address set [%08x]\n", m_selected_channel, m_channel[channel].m_base_address);
+ break;
+ case 0x07: // Address (highest)
+ m_channel[channel].m_base_address =
+ (m_channel[channel].m_base_address & 0x00ffffff) | (data << 24);
+ if (m_base == 0)
+ m_channel[channel].m_address =
+ (m_channel[channel].m_address & 0x00ffffff) | (data << 24);
+ logerror("DMA: Channel %i Address set [%08x]\n", m_selected_channel, m_channel[channel].m_base_address);
+ break;
+ case 0x0a: // Mode control
+ m_channel[channel].m_mode = data;
+ // clear terminal count
+ m_status &= ~(1 << channel);
+
+ logerror("DMA: Channel %i Mode control set [%02x]\n",m_selected_channel,m_channel[channel].m_mode);
+ break;
+
+ case 0x08: // Device control (low)
+ m_command = data;
+ logerror("DMA: Device control low set [%02x]\n",data);
+ break;
+ case 0x09: // Device control (high)
+ m_command_high = data;
+ logerror("DMA: Device control high set [%02x]\n",data);
+ break;
+ case 0x0e: // Request
+ //m_reg.request = data;
+ logerror("(invalid) DMA: Request set [%02x]\n",data); // no software requests on the v53 integrated version
+ break;
+ case 0x0f: // Mask
+ m_mask = data & 0x0f;
+ logerror("DMA: Mask set [%02x]\n",data);
+ break;
+
+
+ }
+ trigger(1);
+
+}