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

                                                                            



                                                     

                                                                            
                
                    
 
 


                                                                            
 

                     
 
 


                                                                            
 
                                                                                               
 
                                                                                                                               
                                                                         
 

 
                                                                                                                                                 
                                                                       
 

 
                                                                          
 
                               
         

                                                                                                                        


            
                                                                      


         
                                                                          
 
                               
         
                                                               


            
                                                                               


         
                                                                                      
 
                               
         

                                                                                                                        


            
                                                                                      


         
                                                                                      
 
                               
         
                                                                      


            
                                                                                      


         
                                                                                                       
 
                                                                                                                                     
                                                                               


 
                                                                                                                                                       
                                                                       
 

 
                                                                             
 

                                












                                                                                              


                                      







                                                                                         

         
                 

 
                                                                             
 

                                







                                                                                       
         
                                      
         







                                                                                         

         
                 

 
                                                                                         
 

                                










                                                                                             


                                      







                                                                                         


         
                                                                                         
 
                                
         







                                                                                       
         
                                      
         







                                                                                         


         



                                                
                                                                                                                           
 
                                                                                                                                                     
                                                                                        
                                                           






                                   

                  




                                                     
                                                 

                                       
                                                                                     
 






                                                 



                                                         
                                                      





                              
                                                                        




                                                           
                                                        
 













                                       
                                                          
 
                            



                                                      

                                                                            

                                               




                                                 

         


                                                                                                               









                                       
                                                           
 
                                                                                                             





                                        
                                                             

                                                           
 
                                                                                                          
                                                                           
 
                                                             
                         
                                                             

                                                                        
                                                                                           

                                                                    

                                                                                   



                                                                                               
                                                                                           
                                 
                                                                                            
 
                                                              





                                          
                                                            

                                                          

                                                       
                                                                          


                                                            
                                                                                 
                                                             
                                                                                   




                                               
                                                            





                                                    

                                 
                                                                              
         
                                                                                     
                                          

                                               




                                                                                                              

                                              







                                                                                                                 
                                                                                                                                                                                        

                 
                                             

                                            
                                                   

                                          

                                                                              



                                            
                                                                                
                                                                             




                                           
                                      
 
                                                               
                 
                                                                            
                                                                                     

                                    
                                                                  


                         

                                
 
// license:BSD-3-Clause
// copyright-holders:smf
/***************************************************************************

    idectrl.c

    Generic (PC-style) IDE controller implementation.

***************************************************************************/

#include "emu.h"
#include "idectrl.h"


/***************************************************************************
    DEBUGGING
***************************************************************************/

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


/***************************************************************************
    CONSTANTS
***************************************************************************/

DEFINE_DEVICE_TYPE(IDE_CONTROLLER, ide_controller_device, "idectrl", "IDE Controller (16-bit)")

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

ide_controller_device::ide_controller_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
	abstract_ata_interface_device(mconfig, type, tag, owner, clock)
{
}

uint16_t ide_controller_device::read_cs0(offs_t offset, uint16_t mem_mask)
{
	if (ACCESSING_BITS_0_7)
	{
		if (ACCESSING_BITS_8_15 && offset == 1) { offset = 0; popmessage("requires ide_controller_32_device"); }
		return internal_read_cs0(offset * 2, mem_mask);
	}
	else
	{
		return internal_read_cs0((offset * 2) + 1, 0xff) << 8;
	}
}

uint16_t ide_controller_device::read_cs1(offs_t offset, uint16_t mem_mask)
{
	if (ACCESSING_BITS_0_7)
	{
		return internal_read_cs1(offset * 2, mem_mask);
	}
	else
	{
		return internal_read_cs1((offset * 2) + 1, mem_mask >> 8) << 8;
	}
}

void ide_controller_device::write_cs0(offs_t offset, uint16_t data, uint16_t mem_mask)
{
	if (ACCESSING_BITS_0_7)
	{
		if (ACCESSING_BITS_8_15 && offset == 1) { offset = 0; popmessage("requires ide_controller_32_device"); }
		return internal_write_cs0(offset * 2, data, mem_mask);
	}
	else
	{
		return internal_write_cs0((offset * 2) + 1, data >> 8, mem_mask >> 8);
	}
}

void ide_controller_device::write_cs1(offs_t offset, uint16_t data, uint16_t mem_mask)
{
	if (ACCESSING_BITS_0_7)
	{
		return internal_write_cs1(offset * 2, data, mem_mask);
	}
	else
	{
		return internal_write_cs1((offset * 2) + 1, data >> 8, mem_mask >> 8);
	}
}

DEFINE_DEVICE_TYPE(IDE_CONTROLLER_32, ide_controller_32_device, "idectrl32", "IDE Controller (32-bit)")

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

ide_controller_32_device::ide_controller_32_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
	abstract_ata_interface_device(mconfig, type, tag, owner, clock)
{
}

uint32_t ide_controller_32_device::read_cs0(offs_t offset, uint32_t mem_mask)
{
	if (ACCESSING_BITS_0_15)
	{
		if (ACCESSING_BITS_0_7)
		{
			uint32_t data = internal_read_cs0((offset * 4), mem_mask);

			if (offset == 0 && ACCESSING_BITS_16_31)
				data |= internal_read_cs0((offset * 4), mem_mask >> 16) << 16;

			return data;
		}
		else
		{
			return internal_read_cs0((offset * 4) + 1, mem_mask >> 8) << 8;
		}
	}
	else if (ACCESSING_BITS_16_31)
	{
		if (ACCESSING_BITS_16_23)
		{
			return internal_read_cs0((offset * 4) + 2, mem_mask >> 16) << 16;
		}
		else
		{
			return internal_read_cs0((offset * 4) + 3, mem_mask >> 24) << 24;
		}
	}

	return 0;
}

uint32_t ide_controller_32_device::read_cs1(offs_t offset, uint32_t mem_mask)
{
	if (ACCESSING_BITS_0_15)
	{
		if (ACCESSING_BITS_0_7)
		{
			return internal_read_cs1((offset * 4), mem_mask);
		}
		else
		{
			return internal_read_cs1((offset * 4) + 1, mem_mask >> 8) << 8;
		}
	}
	else if (ACCESSING_BITS_16_31)
	{
		if (ACCESSING_BITS_16_23)
		{
			return internal_read_cs1((offset * 4) + 2, mem_mask >> 16) << 16;
		}
		else
		{
			return internal_read_cs1((offset * 4) + 3, mem_mask >> 24) << 24;
		}
	}

	return 0;
}

void ide_controller_32_device::write_cs0(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	if (ACCESSING_BITS_0_15)
	{
		if (ACCESSING_BITS_0_7)
		{
			internal_write_cs0((offset * 4), data, mem_mask);

			if (offset == 0 && ACCESSING_BITS_16_31)
				internal_write_cs0((offset * 4), data >> 16, mem_mask >> 16);
		}
		else
		{
			internal_write_cs0((offset * 4) + 1, data >> 8, mem_mask >> 8);
		}
	}
	else if (ACCESSING_BITS_16_31)
	{
		if (ACCESSING_BITS_16_23)
		{
			internal_write_cs0((offset * 4) + 2, data >> 16, mem_mask >> 16);
		}
		else
		{
			internal_write_cs0((offset * 4) + 3, data >> 24, mem_mask >> 24);
		}
	}
}

void ide_controller_32_device::write_cs1(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	if (ACCESSING_BITS_0_15)
	{
		if (ACCESSING_BITS_0_7)
		{
			internal_write_cs1((offset * 4), data, mem_mask);
		}
		else
		{
			internal_write_cs1((offset * 4) + 1, data >> 8, mem_mask >> 8);
		}
	}
	else if (ACCESSING_BITS_16_31)
	{
		if (ACCESSING_BITS_16_23)
		{
			internal_write_cs1((offset * 4) + 2, data >> 16, mem_mask >> 16);
		}
		else
		{
			internal_write_cs1((offset * 4) + 3, data >> 24, mem_mask >> 24);
		}
	}
}

#define IDE_BUSMASTER_STATUS_ACTIVE         0x01
#define IDE_BUSMASTER_STATUS_ERROR          0x02
#define IDE_BUSMASTER_STATUS_IRQ            0x04

DEFINE_DEVICE_TYPE(BUS_MASTER_IDE_CONTROLLER, bus_master_ide_controller_device, "idectrl32bm", "Bus Master IDE Controller")

bus_master_ide_controller_device::bus_master_ide_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	ide_controller_32_device(mconfig, BUS_MASTER_IDE_CONTROLLER, tag, owner, clock),
	m_dma_space(*this, finder_base::DUMMY_TAG, -1, 32),
	m_dma_address(0),
	m_dma_bytes_left(0),
	m_dma_descriptor(0),
	m_dma_last_buffer(0),
	m_bus_master_command(0),
	m_bus_master_status(0),
	m_bus_master_descriptor(0),
	m_irq(0),
	m_dmarq(0)
{
}

void bus_master_ide_controller_device::device_start()
{
	ide_controller_32_device::device_start();

	/* find the bus master space */
	m_dma_address_xor = (m_dma_space->endianness() == ENDIANNESS_LITTLE) ? 0 : 3;

	save_item(NAME(m_dma_address));
	save_item(NAME(m_dma_bytes_left));
	save_item(NAME(m_dma_descriptor));
	save_item(NAME(m_dma_last_buffer));
	save_item(NAME(m_bus_master_command));
	save_item(NAME(m_bus_master_status));
	save_item(NAME(m_bus_master_descriptor));
}

void bus_master_ide_controller_device::set_irq(int state)
{
	abstract_ata_interface_device::set_irq(state);

	if (m_irq != state)
	{
		m_irq = state;

		if( m_irq )
			m_bus_master_status |= IDE_BUSMASTER_STATUS_IRQ;
	}
}

void bus_master_ide_controller_device::set_dmarq(int state)
{
	abstract_ata_interface_device::set_dmarq(state);

	if (m_dmarq != state)
	{
		m_dmarq = state;

		execute_dma();
	}
}

/*************************************
 *
 *  Bus master read
 *
 *************************************/

READ32_MEMBER( bus_master_ide_controller_device::bmdma_r )
{
	uint32_t result = 0;
	switch( offset )
	{
	case 0:
		/* command register/status register */
		result = m_bus_master_command | (m_bus_master_status << 16);
		break;
	case 1:
		/* descriptor table register */
		result = m_bus_master_descriptor;
		break;
	default:
		result = 0xffffffff;
		break;
	}

	LOG("%s:ide_bus_master32_r(%d, %08x, %08x)\n", machine().describe_context(), offset, mem_mask, result);

	return result;
}



/*************************************
 *
 *  Bus master write
 *
 *************************************/

WRITE32_MEMBER( bus_master_ide_controller_device::bmdma_w )
{
	LOG("%s:ide_bus_master32_w(%d, %08x, %08X)\n", machine().describe_context(), offset, mem_mask, data);

	switch( offset )
	{
	case 0:
		if( ACCESSING_BITS_0_7 )
		{
			/* Bus Master IDE Command register */
			uint8_t old = m_bus_master_command;
			uint8_t val = data & 0xff;

			/* save the "Read or Write Control" bit 3 and the "Start/Stop Bus Master" bit 0 */
			m_bus_master_command = (old & 0xf6) | (val & 0x09);

			if ((old ^ m_bus_master_command) & 1)
			{
				if (m_bus_master_command & 1)
				{
					/* handle starting a transfer */
					m_bus_master_status |= IDE_BUSMASTER_STATUS_ACTIVE;

					/* reset all the DMA data */
					m_dma_bytes_left = 0;
					m_dma_descriptor = m_bus_master_descriptor;

					/* if we're going live, start the pending read/write */
					execute_dma();
				}
				else if (m_bus_master_status & IDE_BUSMASTER_STATUS_ACTIVE)
				{
					m_bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE;

					LOG("DMA Aborted!\n");
				}
			}
		}

		if( ACCESSING_BITS_16_23 )
		{
			/* Bus Master IDE Status register */
			uint8_t old = m_bus_master_status;
			uint8_t val = data >> 16;

			/* save the DMA capable bits */
			m_bus_master_status = (old & 0x9f) | (val & 0x60);

			/* clear interrupt and error bits */
			if (val & IDE_BUSMASTER_STATUS_IRQ)
				m_bus_master_status &= ~IDE_BUSMASTER_STATUS_IRQ;
			if (val & IDE_BUSMASTER_STATUS_ERROR)
				m_bus_master_status &= ~IDE_BUSMASTER_STATUS_ERROR;
		}
		break;

	case 1:
		/* descriptor table register */
		m_bus_master_descriptor = data & 0xfffffffc;
		break;
	}
}

void bus_master_ide_controller_device::execute_dma()
{
	write_dmack(ASSERT_LINE);

	while (m_dmarq && (m_bus_master_status & IDE_BUSMASTER_STATUS_ACTIVE))
	{
		/* if we're out of space, grab the next Physical Region Descriptor */
		if (m_dma_bytes_left == 0)
		{
			/* fetch the address */
			m_dma_address = m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor);
			m_dma_address |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 8;
			m_dma_address |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 16;
			m_dma_address |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 24;
			m_dma_address &= 0xfffffffe;

			/* fetch the length */
			m_dma_bytes_left = m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor);
			m_dma_bytes_left |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 8;
			m_dma_bytes_left |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 16;
			m_dma_bytes_left |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 24;
			m_dma_last_buffer = (m_dma_bytes_left >> 31) & 1;
			m_dma_bytes_left &= 0xfffe;
			if (m_dma_bytes_left == 0)
				m_dma_bytes_left = 0x10000;
			LOG("New DMA descriptor: address = %08X  bytes = %04X  last = %d time: %s\n", m_dma_address, m_dma_bytes_left, m_dma_last_buffer, machine().time().as_string());
		}

		if (m_bus_master_command & 8)
		{
			// read from ata bus
			uint16_t data = read_dma();

			// write to memory
			m_dma_space->write_byte(m_dma_address++, data & 0xff);
			m_dma_space->write_byte(m_dma_address++, data >> 8);
		}
		else
		{
			// read from memory;
			uint16_t data = m_dma_space->read_byte(m_dma_address++);
			data |= m_dma_space->read_byte(m_dma_address++) << 8;

			// write to ata bus
			write_dma(data);
		}

		m_dma_bytes_left -= 2;

		if (m_dma_bytes_left == 0 && m_dma_last_buffer)
		{
			m_bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE;
			LOG("DMA Complete time: %s\n", machine().time().as_string());
			if (m_dmarq)
			{
				LOG("DMA Out of buffer space!\n");
			}
		}
	}

	write_dmack(CLEAR_LINE);
}