summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/am9517a.cpp
blob: cd6955b63ed02b333ca71114c0259f15a3649929 (plain) (tree)
1
2
3
4
5
6
7
8
9

                               

                                                                            
               

                
 
                                            
 



                                                                     
 



                                                                            
         
 
                  


  

  

                                                                             
 





                                                    
 
                                             


  
                

                    


                     





                                                                            


                                                                                        





                                                                            

















                                                   





















                                                                                

































                                                                            
                                                                    








                                                  
                   








                                                          
                                                                                   













                                                                                             
            





                                                   
                                     













                                                     



                                                                          











                                                   
                                    

































                                                               
                                 
                                                                


                                
                                              














                                                               





                                                                                     


                                 
                                              


                                
                                                                



















                                                                                  
                                                                                 
 







                                                                                    
                                                                                 
 
































                                                                                    
 


                                                          
 










                                                   
                                     

                         











                                                       













                                                                                                     
                             
                    

                               














                                                                            
 

                                                                                                                                 

                                                         


                             



                                     


                                                                           



 
                                                                                                               
                                                             


 
                                                                                                                         
                                                              


 
                                                                                                                         
                                                                  


 






                                                   
                                

                            



                                     







                                     
         




                                        


                       




                                 
                                 






                                           
 







                                                                


                                

















                                                   

                    

                    
                             















                                                   
                                            
























                                                                                                                                  





                                                                                                                                                      

                                 




                                                               






                                    
                                                                                                    
                         




                                                               

                              


                                                                  
                                            

                                                       
                         




                                                               



                                   







                                                                                  
 




                                                   
                                            







                                                                
 












                                                         
 












                                              
 




                                            
 




                                              
 


                                            
 


                                            
 


                                      





                                                                         
                                                                                         



                                                                         
                                                                                         

                         








                                                   
          



                                                   
                         







































                                                                           
                                         




                                        
 










                                                   
           






                                                   
 













                                                                                                                             
                                                                                                                   













                                                                                                                         
                                                                                                                    











                                         
                                                                           








                                                                          



                                                                            





                                                                           
                                                                                   

                              
 












                                                                  
                                                                             

                              
 








                                                                        
                                                                                             

                              
 
                                           
                                                                      


                                  
 
                                           
                                                      
 

                                       
 
                                         
                                                             


                                   
 


                                             
                                                                     


                              
                   








                                                   
                                                     

                       
                   








                                                   
                                          










                                                   
                                                   








































                                                   




                                                   




















                                            

                                       
                        

                                         
                                                     
 


















































                                                                                       
                                                    






















                                                                                            



                                         
                                         
 





                                                   
                                         

















































































                                                                                                                                   
                   
 
 





















































                                                                                                     
// 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 "emu.h"
#include "am9517a.h"

//#define VERBOSE 1
#include "logmacro.h"



//**************************************************************************
//  DEVICE DEFINITIONS
//**************************************************************************

DEFINE_DEVICE_TYPE(AM9517A,      am9517a_device,      "am9517a",  "AM9517A")
DEFINE_DEVICE_TYPE(V53_DMAU,     upd71071_v53_device, "v53_dmau", "V53 DMAU")
DEFINE_DEVICE_TYPE(PCXPORT_DMAC, pcxport_dmac_device, "pcx_dmac", "PC Transporter DMAC")


//**************************************************************************
//  MACROS / CONSTANTS
//**************************************************************************


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)
{
	LOG("AM9517A Channel %u DMA Request: %u\n", 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 == m_current_channel) && !COMMAND_MEM_TO_MEM)
			m_out_dack_cb[channel](COMMAND_DACK_ACTIVE_HIGH);
		else
			m_out_dack_cb[channel](!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:
		m_temp = m_in_ior_cb[m_current_channel](offset);
		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_t v1 = m_in_memr_cb(offset);
			if(0 && m_temp != v1)
				logerror("verify error %02x vs. %02x\n", m_temp, v1);
		}
		break;

	case MODE_TRANSFER_WRITE:
		m_out_memw_cb(offset, m_temp);
		break;

	case MODE_TRANSFER_READ:
		m_out_iow_cb[m_current_channel](offset, m_temp);
		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 -
//-------------------------------------------------

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 *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, type, tag, owner, clock),
		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_cb{ { *this }, { *this }, { *this }, { *this } },
		m_out_iow_cb{ { *this }, { *this }, { *this }, { *this } },
		m_out_dack_cb{ { *this }, { *this }, { *this }, { *this } }
{
}


am9517a_device::am9517a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: am9517a_device(mconfig, AM9517A, tag, owner, clock)
{
}

upd71071_v53_device::upd71071_v53_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: am9517a_device(mconfig, V53_DMAU, tag, owner, clock)
{
}

pcxport_dmac_device::pcxport_dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: am9517a_device(mconfig, PCXPORT_DMAC, tag, owner, clock)
{
}

//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void am9517a_device::device_start()
{
	// set our instruction counter
	set_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();
	for(auto &cb : m_in_ior_cb)
		cb.resolve_safe(0);
	for(auto &cb : m_out_iow_cb)
		cb.resolve_safe();
	for(auto &cb : m_out_dack_cb)
		cb.resolve_safe();

	for(auto &elem : m_channel)
	{
		elem.m_address = 0;
		elem.m_count = 0;
		elem.m_base_address = 0;
		elem.m_base_count = 0;
		elem.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_t 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;
			}

			LOG("AM9517A Channel %u Base Address: %04x\n", 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;
			}

			LOG("AM9517A Channel %u Base Word Count: %04x\n", channel, m_channel[channel].m_base_count);
			break;
		}

		m_msb = !m_msb;
	}
	else
	{
		switch (offset & 0x0f)
		{
		case REGISTER_COMMAND:
			m_command = data;

			LOG("AM9517A Command Register: %02x\n", 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));
				}

				LOG("AM9517A Request Register: %01x\n", m_request);
			}
			break;

		case REGISTER_SINGLE_MASK:
			{
				int channel = data & 0x03;

				if (BIT(data, 2))
				{
					m_mask |= (1 << channel);
				}
				else
				{
					m_mask &= ~(1 << channel);
				}

				LOG("AM9517A Mask Register: %01x\n", m_mask);
			}
			break;

		case REGISTER_MODE:
			{
				int channel = data & 0x03;

				m_channel[channel].m_mode = data & 0xfc;

				// clear terminal count
				m_status &= ~(1 << channel);

				LOG("AM9517A Channel %u Mode: %02x\n", channel, data & 0xfc);
			}
			break;

		case REGISTER_BYTE_POINTER:
			LOG("AM9517A Clear Byte Pointer Flip-Flop\n");

			m_msb = 0;
			break;

		case REGISTER_MASTER_CLEAR:
			LOG("AM9517A Master Clear\n");

			device_reset();
			break;

		case REGISTER_CLEAR_MASK:
			LOG("AM9517A Clear Mask Register\n");

			m_mask = 0;
			break;

		case REGISTER_MASK:
			m_mask = data & 0x0f;

			LOG("AM9517A Mask Register: %01x\n", m_mask);
			break;
		}
	}
	trigger(1);
}


//-------------------------------------------------
//  hack_w - hold acknowledge
//-------------------------------------------------

WRITE_LINE_MEMBER( am9517a_device::hack_w )
{
	LOG("AM9517A Hold Acknowledge: %u\n", state);

	m_hack = state;
	trigger(1);
}


//-------------------------------------------------
//  ready_w - ready
//-------------------------------------------------

WRITE_LINE_MEMBER( am9517a_device::ready_w )
{
	LOG("AM9517A Ready: %u\n", state);

	m_ready = state;
}


//-------------------------------------------------
//  eop_w - end of process
//-------------------------------------------------

WRITE_LINE_MEMBER( am9517a_device::eop_w )
{
	LOG("AM9517A End of Process: %u\n", 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_t ret = 0;
	int channel = m_selected_channel;

	LOG("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);

}

void pcxport_dmac_device::device_reset()
{
	m_state = STATE_SI;
	m_command = 0;
	m_status = 0;
	m_request = 0;
	m_mask = 0;
	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();
}

void pcxport_dmac_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;
	}
	// don't mask out channel if not autoinitialize

	// signal end of process
	set_eop(ASSERT_LINE);
	set_hreq(0);

	m_current_channel = -1;
	set_dack();

	m_state = STATE_SI;
}