summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/wd33c93.cpp
blob: ec9c80174344905122c1049f5150e64041bbac6f (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
                       
                                                   












                                                  
                

                    
                 

                     
 
                 




























                                        

                  





                                        

                     





                                        


                                         


































































                                              
 
                            
                                 

                                            
                                                    

 
                                                

                           


                                                               

 
                                    

                           
                                                  

                    
                                           
                    
                                               



                     
                                                     

                             
                           

                                
                                             

                                   
                                             

                                        
                                   

                                           
                                                     



                                             
                                                      


                                                    
                                                          

                                            
                               
         
                            


         
                                                                                              
 




                                            
 


                                                           
 



                                                      

 
                                                   

                                                      
                                                            


                      
                                        
 
                                                                                                                       

                                  
                                    

 
                                  
 








                                                                                                                 

                                                                
                                          




                                     
                                          

                                  
                                                          

 
                                

                                  
                                

 
                                     

                                  
                                                          

 
                                 
 

                                 

                                              
                         




                                                                           
                                                                  

                                                                                                     
                                                



                                                                     
                                               


                                                                  
                                                                     







                                             
                                

 
                                     
 

                                 

                                              
                         
         
                                                    

                                                 


                                            

                                                          

                                                
                                                                
                         

                                                                                                                                            




                                                       
                                                         



                                              
                                   
                 
                                                 
 
                                                                             
 
                                                                    
                                                       

                                           

                 


                                              




                                                                    
                                      

                                                         
                                               

                                                                          
                                                                             






                                             
                                    


                                  
                                

 
                                 



                                             
                                                          

 
                                   

                                                  

                                             

                                                                        
                                                             

 
                             
                                       

                             
                                              
 
                   
         


                            
 


                            
 










































                                     
 



                              

 
                                    





                                                    
                                           




                       
                                                                                                                       

                                                 
                                          

                                                                             
                                                 
                         
                                                                                                                                          

                                                                
                                                                     

                                                         
                                                   
                         
                                                    
                         
                                                           
                         
                                                   

                                                                                              
                                                             
 
                                                              




                                                           
                                                                   
                                         
                                                                        


                                                          
                                                                



                                                                                              

                                                                                      
 
                                                                  



                                                                                
                                                                             

                                                                                                                                               
                                                                                       
 
                                                                                   




                                                                         
                                                                              


                                                                                                                                                 


                                                                                           

                                                                                
                                                                             

                                                                                       
                                                                                            



                                                                                       
                                                                                              


                                                                                       

                                                                                               


                                                                                        
                                                                                                







                                                                                              
                                                                                           

                                                                                
                                                                             

                                                                                          
                                                                                      




                                                                          
                                                                                             








                                                                                                                              
                                                                                                   
                         
                                                           











                                                                                                      
                                  





                                             
                                                         
                 


                       
                                    

                                                               
                                                     
                         
                                                                      
 
                                                       
                                 
                                                    

                                 
                                                                                                                                
                         
                                                   



                                                                               
                                                             

                                                                 
                                                  
 
                                                                            

                                                                
                                                               
                                 
                                                                                

                                                              
                                                            

                                                                      
                                                               

                                                                  
                                                                               


                                                                                                  
                                                           
                                         
                                                                         

                                                                                     
                                                                               

                                                                   

                                         
                                                                              

                                                              

                                                                                             

                                                              
                                                                



                                                                                   
                                                                                     

                                                                                  
                                                                              

                                                                                  
                                                                                               


                                                    

                                                                                              




                                                 
                                                                                                               

                                                    
                                         

                                                                                        
                                                                                                   
                         
                                                           














                                                                                     
                                                                                                                 
                                                                      
                       
 
 
 

                                   

                                                 
                                      








                                                  
 
                           

                                           













                                            
 
                                                               
 
                        
 

                                       



                       
                                                     




                                                                                         

                    
                                                          
 


                                     

 
                                                              
 
                                 

 
                                

                                                                   

                                              

 
                                   
 
                                
 
 
                                                                                      
// license:BSD-3-Clause
// copyright-holders:ElSemi, R. Belmont, Ryan Holtz
/*
 * wd33c93.c
 *
 * WD/AMD 33c93 SCSI controller, as seen in
 * early PCs, some MSX add-ons, NEC PC-88, and SGI
 * Indigo, Indigo2, and Indy systems.
 *
 * References:
 * WD 33c93 manual
 * NetBSD 33c93 driver
 *
 */

#include "emu.h"
#include "wd33c93.h"

#define VERBOSE 1
#include "logmacro.h"


/* WD commands */
#define WD_CMD_RESET                0x00
#define WD_CMD_ABORT                0x01
#define WD_CMD_ASSERT_ATN           0x02
#define WD_CMD_NEGATE_ACK           0x03
#define WD_CMD_DISCONNECT           0x04
#define WD_CMD_RESELECT             0x05
#define WD_CMD_SEL_ATN              0x06
#define WD_CMD_SEL                  0x07
#define WD_CMD_SEL_ATN_XFER         0x08
#define WD_CMD_SEL_XFER             0x09
#define WD_CMD_RESEL_RECEIVE        0x0a
#define WD_CMD_RESEL_SEND           0x0b
#define WD_CMD_WAIT_SEL_RECEIVE     0x0c
#define WD_CMD_SSCC                 0x0d
#define WD_CMD_SND_DISC             0x0e
#define WD_CMD_SET_IDI              0x0f
#define WD_CMD_RCV_CMD              0x10
#define WD_CMD_RCV_DATA             0x11
#define WD_CMD_RCV_MSG_OUT          0x12
#define WD_CMD_RCV                  0x13
#define WD_CMD_SND_STATUS           0x14
#define WD_CMD_SND_DATA             0x15
#define WD_CMD_SND_MSG_IN           0x16
#define WD_CMD_SND                  0x17
#define WD_CMD_TRANS_ADDR           0x18
#define WD_CMD_XFER_PAD             0x19
#define WD_CMD_TRANS_INFO           0x20
#define WD_CMD_TRANSFER_PAD         0x21
#define WD_CMD_SBT_MODE             0x80

/* ASR register */
#define ASR_INT                     0x80
#define ASR_LCI                     0x40
#define ASR_BSY                     0x20
#define ASR_CIP                     0x10
#define ASR_PE                      0x02
#define ASR_DBR                     0x01

/* SCSI Bus Phases */
#define PHS_DATA_OUT                0x00
#define PHS_DATA_IN                 0x01
#define PHS_COMMAND                 0x02
#define PHS_STATUS                  0x03
#define PHS_MESS_OUT                0x06
#define PHS_MESS_IN                 0x07

/* Command Status Register definitions */

	/* reset state interrupts */
#define CSR_RESET                   0x00
#define CSR_RESET_AF                0x01

	/* successful completion interrupts */
#define CSR_RESELECT                0x10
#define CSR_SELECT                  0x11
#define CSR_SEL_XFER_DONE           0x16
#define CSR_XFER_DONE               0x18

	/* paused or aborted interrupts */
#define CSR_MSGIN                   0x20
#define CSR_SDP                     0x21
#define CSR_SEL_ABORT               0x22
#define CSR_RESEL_ABORT             0x25
#define CSR_RESEL_ABORT_AM          0x27
#define CSR_ABORT                   0x28

	/* terminated interrupts */
#define CSR_INVALID                 0x40
#define CSR_UNEXP_DISC              0x41
#define CSR_TIMEOUT                 0x42
#define CSR_PARITY                  0x43
#define CSR_PARITY_ATN              0x44
#define CSR_BAD_STATUS              0x45
#define CSR_UNEXP                   0x48

	/* service required interrupts */
#define CSR_RESEL                   0x80
#define CSR_RESEL_AM                0x81
#define CSR_DISC                    0x85
#define CSR_SRV_REQ                 0x88

	/* Own ID/CDB Size register */
#define OWNID_EAF                   0x08
#define OWNID_EHP                   0x10
#define OWNID_RAF                   0x20
#define OWNID_FS_8                  0x00
#define OWNID_FS_12                 0x40
#define OWNID_FS_16                 0x80

	/* Control register */
#define CTRL_HSP                    0x01
#define CTRL_HA                     0x02
#define CTRL_IDI                    0x04
#define CTRL_EDI                    0x08
#define CTRL_HHP                    0x10
#define CTRL_POLLED                 0x00
#define CTRL_BURST                  0x20
#define CTRL_BUS                    0x40
#define CTRL_DMA                    0x80

	/* Synchronous Transfer Register */
#define STR_FSS                     0x80

	/* Destination ID register */
#define DSTID_DPD                   0x40
#define DATA_OUT_DIR                0
#define DATA_IN_DIR                 1
#define DSTID_SCC                   0x80

	/* Source ID register */
#define SRCID_MASK                  0x07
#define SRCID_SIV                   0x08
#define SRCID_DSP                   0x20
#define SRCID_ES                    0x40
#define SRCID_ER                    0x80

/* convernience functions */
uint8_t wd33c93_device::getunit()
{
	/* return the destination unit id */
	return regs[WD_DESTINATION_ID] & SRCID_MASK;
}

void wd33c93_device::set_xfer_count( int count )
{
	/* set the count */
	regs[ WD_TRANSFER_COUNT_LSB ] = count & 0xff;
	regs[ WD_TRANSFER_COUNT ] = ( count >> 8 ) & 0xff;
	regs[ WD_TRANSFER_COUNT_MSB ] = ( count >> 16 ) & 0xff;
}

int wd33c93_device::get_xfer_count()
{
	/* get the count */
	int count = regs[ WD_TRANSFER_COUNT_MSB ];

	count <<= 8;
	count |= regs[ WD_TRANSFER_COUNT ];
	count <<= 8;
	count |= regs[ WD_TRANSFER_COUNT_LSB ];

	return count;
}

void wd33c93_device::complete_immediate( int status )
{
	/* reset our timer */
	cmd_timer->reset();

	/* set the new status */
	regs[WD_SCSI_STATUS] = status & 0xff;

	/* set interrupt pending */
	regs[WD_AUXILIARY_STATUS] |= ASR_INT;

	/* check for error conditions */
	if ( get_xfer_count() > 0 )
	{
		/* set data buffer ready */
		regs[WD_AUXILIARY_STATUS] |= ASR_DBR;
	}
	else
	{
		/* clear data buffer ready */
		regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR;
	}

	/* clear command in progress and bus busy */
	regs[WD_AUXILIARY_STATUS] &= ~(ASR_CIP | ASR_BSY);

	/* if we have a callback, call it */
	if (!m_irq_cb.isnull())
	{
		m_irq_cb(1);
	}
}

void wd33c93_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
{
	switch( tid )
	{
	case 0:
		complete_immediate( param );
		break;

	case 1:
		complete_immediate(CSR_SRV_REQ | busphase);
		break;

	case 2:
		regs[WD_AUXILIARY_STATUS] &= ~ASR_CIP;
		break;
	}
}

void wd33c93_device::complete_cmd( uint8_t status )
{
	/* fire off a timer to complete the command */
	cmd_timer->adjust( attotime::from_usec(1), status );
}

/* command handlers */
void wd33c93_device::unimplemented_cmd()
{
	logerror( "%s:Unimplemented SCSI controller command: %02x\n", machine().describe_context(), regs[WD_COMMAND] );

	/* complete the command */
	complete_cmd( CSR_INVALID );
}

void wd33c93_device::invalid_cmd()
{
	logerror( "%s:Invalid SCSI controller command: %02x\n", machine().describe_context(), regs[WD_COMMAND] );

	/* complete the command */
	complete_cmd( CSR_INVALID );
}

void wd33c93_device::reset_cmd()
{
	int advanced = 0;

	/* see if it wants us to reset with advanced features */
	if ( regs[WD_OWN_ID] & OWNID_EAF )
	{
		advanced = 1;
	}

	/* clear out all registers */
	memset( regs, 0, sizeof( regs ) );

	/* complete the command */
	complete_cmd(advanced ? CSR_RESET_AF : CSR_RESET);
}

void wd33c93_device::abort_cmd()
{
	/* complete the command */
	complete_cmd(CSR_ABORT);
}

void wd33c93_device::disconnect_cmd()
{
	/* complete the command */
	regs[WD_AUXILIARY_STATUS] &= ~(ASR_CIP | ASR_BSY);
}

void wd33c93_device::select_cmd()
{
	uint8_t unit = getunit();
	uint8_t newstatus;

	/* see if we can select that device */
	if (select(unit))
	{
		/* device is available - signal selection done */
		newstatus = CSR_SELECT;

		/* determine the next bus phase depending on the command */
		if ( (regs[WD_COMMAND] & 0x7f) == WD_CMD_SEL_ATN )
		{
			/* /ATN asserted during select: Move to Message Out Phase to read identify */
			busphase = PHS_MESS_OUT;
		}
		else
		{
			/* No /ATN asserted: Move to Command Phase */
			busphase = PHS_COMMAND;
		}

		/* queue up a service request out in the future */
		service_req_timer->adjust( attotime::from_usec(50) );
	}
	else
	{
		/* device is not available */
		newstatus = CSR_TIMEOUT;
	}

	/* complete the command */
	complete_cmd(newstatus);
}

void wd33c93_device::selectxfer_cmd()
{
	uint8_t unit = getunit();
	uint8_t newstatus;

	/* see if we can select that device */
	if (select(unit))
	{
		if ( regs[WD_COMMAND_PHASE] < 0x45 )
		{
			/* device is available */
			int phase;

			/* do the request */
			send_command(&regs[WD_CDB_1], 12);
			phase = get_phase();

			/* set transfer count */
			if ( get_xfer_count() > TEMP_INPUT_LEN )
			{
				logerror( "WD33C93: Transfer count too big. Please increase TEMP_INPUT_LEN (size=%d)\n", get_xfer_count() );
				set_xfer_count( TEMP_INPUT_LEN );
			}

			switch( phase )
			{
				case SCSI_PHASE_DATAIN:
					read_pending = 1;
					break;
			}
		}

		if ( read_pending )
		{
			int len = TEMP_INPUT_LEN;

			if ( get_xfer_count() < len ) len = get_xfer_count();

			memset( &temp_input[0], 0, TEMP_INPUT_LEN );
			read_data(&temp_input[0], len);
			temp_input_pos = 0;
			read_pending = 0;
		}

		regs[WD_TARGET_LUN] = 0;
		regs[WD_CONTROL] |= CTRL_EDI;
		regs[WD_COMMAND_PHASE] = 0x60;

		/* signal transfer ready */
		newstatus = CSR_SEL_XFER_DONE;

		/* if allowed disconnect, queue a service request */
		if ( identify & 0x40 )
		{
			/* queue disconnect message in */
			busphase = PHS_MESS_IN;

			/* queue up a service request out in the future */
			service_req_timer->adjust( attotime::from_usec(50) );
		}
	}
	else
	{
		/* device is not available */
		newstatus = CSR_TIMEOUT;

		set_xfer_count( 0 );
	}

	/* complete the command */
	complete_cmd(newstatus);
}

void wd33c93_device::negate_ack()
{
	logerror( "WD33C93: ACK Negated\n" );

	/* complete the command */
	regs[WD_AUXILIARY_STATUS] &= ~(ASR_CIP | ASR_BSY);
}

void wd33c93_device::xferinfo_cmd()
{
	/* make the buffer available right away */
	regs[WD_AUXILIARY_STATUS] |= ASR_DBR;
	regs[WD_AUXILIARY_STATUS] |= ASR_CIP;

	/* the command will be completed once the data is transferred */
	deassert_cip_timer->adjust( attotime::from_msec(1) );
}

/* Handle pending commands */
void wd33c93_device::dispatch_command()
{
	/* get the command */
	uint8_t cmd = regs[WD_COMMAND] & 0x7f;

	switch(cmd)
	{
	case WD_CMD_RESET:
		reset_cmd();
		break;

	case WD_CMD_ABORT:
		abort_cmd();
		break;

	case WD_CMD_NEGATE_ACK:
		negate_ack();
		break;

	case WD_CMD_DISCONNECT:
		disconnect_cmd();
		break;

	case WD_CMD_SEL_ATN:
	case WD_CMD_SEL:
		select_cmd();
		break;

	case WD_CMD_SEL_ATN_XFER:
	case WD_CMD_SEL_XFER:
		selectxfer_cmd();
		break;

	case WD_CMD_TRANS_INFO:
		xferinfo_cmd();
		break;

	case WD_CMD_ASSERT_ATN:
	case WD_CMD_RESELECT:
	case WD_CMD_RESEL_RECEIVE:
	case WD_CMD_RESEL_SEND:
	case WD_CMD_WAIT_SEL_RECEIVE:
	case WD_CMD_SSCC:
	case WD_CMD_SND_DISC:
	case WD_CMD_SET_IDI:
	case WD_CMD_RCV_CMD:
	case WD_CMD_RCV_DATA:
	case WD_CMD_RCV_MSG_OUT:
	case WD_CMD_RCV:
	case WD_CMD_SND_STATUS:
	case WD_CMD_SND_DATA:
	case WD_CMD_SND_MSG_IN:
	case WD_CMD_SND:
	case WD_CMD_TRANS_ADDR:
	case WD_CMD_XFER_PAD:
	case WD_CMD_TRANSFER_PAD:
		unimplemented_cmd();
		break;

	default:
		invalid_cmd();
		break;
	}
}

WRITE8_MEMBER(wd33c93_device::write)
{
	switch( offset )
	{
		case 0:
		{
			/* update register select */
			sasr = data & 0x1f;
		}
		break;

		case 1:
		{
			LOG( "WD33C93: %s - Write REG=%02x, data = %02x\n", machine().describe_context(), sasr, data );

			/* update the register */
			regs[sasr] = data;

			/* if we receive a command, schedule to process it */
			if ( sasr == WD_COMMAND )
			{
				LOG( "WDC33C93: %s - Executing command %08x - unit %d\n", machine().describe_context(), data, getunit() );

				/* signal we're processing it */
				regs[WD_AUXILIARY_STATUS] |= ASR_CIP;

				/* process the command */
				dispatch_command();
			}
			else if ( sasr == WD_CDB_1 )
			{
				regs[WD_COMMAND_PHASE] = 0;
			}
			else if ( sasr == WD_DATA )
			{
				/* if data was written, and we have a count, send to device */
				int count = get_xfer_count();

				if ( regs[WD_COMMAND] & 0x80 )
					count = 1;

				if ( count-- > 0 )
				{
					/* write to FIFO */
					if ( fifo_pos < FIFO_SIZE )
					{
						fifo[fifo_pos++] = data;
					}

					/* update count */
					set_xfer_count( count );

					/* if we're done with the write, see where we're at */
					if ( count == 0 )
					{
						regs[WD_AUXILIARY_STATUS] |= ASR_INT;
						regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR;

						switch( busphase )
						{
							case PHS_MESS_OUT:
							{
								/* reset fifo */
								fifo_pos = 0;

								/* Message out phase. Data is probably SCSI Identify. Move to command phase. */
								busphase = PHS_COMMAND;

								identify = fifo[0];
							}
							break;

							case PHS_COMMAND:
							{
								int xfercount;
								int phase;

								/* Execute the command. Depending on the command, we'll move to data in or out */
								send_command(&fifo[0], 12);
								xfercount = get_length();
								phase = get_phase();

								/* reset fifo */
								fifo_pos = 0;

								/* set the new count */
								set_xfer_count( xfercount );

								switch( phase )
								{
								case SCSI_PHASE_STATUS:
									busphase = PHS_STATUS;
									break;

								case SCSI_PHASE_DATAIN:
									busphase = PHS_DATA_IN;
									read_pending = 1;
									break;

								case SCSI_PHASE_DATAOUT:
									busphase = PHS_DATA_OUT;
									break;
								}
							}
							break;

							case PHS_DATA_OUT:
							{
								/* write data out to device */
								write_data(fifo, fifo_pos);

								/* reset fifo */
								fifo_pos = 0;

								/* move to status phase */
								busphase = PHS_STATUS;
							}
							break;
						}

						/* complete the command */
						complete_immediate(CSR_XFER_DONE | busphase);
					}
				}
				else
				{
					logerror( "WD33C93: Sending data to device with transfer count = 0!. Ignoring...\n" );
				}
			}

			/* auto-increment register select if not on special registers */
			if ( sasr != WD_COMMAND && sasr != WD_DATA && sasr != WD_AUXILIARY_STATUS )
			{
				sasr = ( sasr + 1 ) & 0x1f;
			}
		}
		break;

		default:
		{
			logerror( "WD33C93: Write to invalid offset %d (data=%02x)\n", offset, data );
		}
		break;
	}
}

READ8_MEMBER(wd33c93_device::read)
{
	switch( offset )
	{
		case 0:
		{
			/* read aux status */
			return regs[WD_AUXILIARY_STATUS];
		}

		case 1:
		{
			uint8_t ret;

			/* if reading status, clear irq flag */
			if ( sasr == WD_SCSI_STATUS )
			{
				regs[WD_AUXILIARY_STATUS] &= ~ASR_INT;

				if (!m_irq_cb.isnull())
				{
					m_irq_cb(0);
				}

				LOG( "WD33C93: %s - Status read (%02x)\n", machine().describe_context(), regs[WD_SCSI_STATUS] );
			}
			else if ( sasr == WD_DATA )
			{
				/* we're going to be doing synchronous reads */

				/* get the transfer count */
				int count = get_xfer_count();

				/* initialize the return value */
				regs[WD_DATA] = 0;

				if ( count <= 0 && busphase == PHS_MESS_IN )
				{
					/* move to disconnect */
					complete_cmd(CSR_DISC);
				}
				else if ( count == 1 && busphase == PHS_STATUS )
				{
					/* update the count */
					set_xfer_count( 0 );

					/* move to message in phase */
					busphase = PHS_MESS_IN;

					/* complete the command */
					complete_cmd(CSR_XFER_DONE | busphase);
				}
				else if ( count-- > 0 ) /* make sure we still have data to send */
				{
					if ( read_pending )
					{
						int len = TEMP_INPUT_LEN;

						if ( (count+1) < len ) len = count+1;
						read_data(&temp_input[0], len);
						temp_input_pos = 0;
						read_pending = 0;
					}

					regs[WD_AUXILIARY_STATUS] &= ~ASR_INT;

					/* read in one byte */
					if ( temp_input_pos < TEMP_INPUT_LEN )
						regs[WD_DATA] = temp_input[temp_input_pos++];

					/* update the count */
					set_xfer_count( count );

					/* transfer finished, see where we're at */
					if ( count == 0 )
					{
						if ( regs[WD_COMMAND_PHASE] != 0x60 )
						{
							/* move to status phase */
							busphase = PHS_STATUS;

							/* complete the command */
							complete_cmd(CSR_XFER_DONE | busphase);
						}
						else
						{
							regs[WD_AUXILIARY_STATUS] |= ASR_INT;
							regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR;
						}
					}
				}
			}

			LOG( "WD33C93: %s - Data read (%02x)\n", machine().describe_context(), regs[WD_DATA] );

			/* get the register value */
			ret = regs[sasr];

			/* auto-increment register select if not on special registers */
			if ( sasr != WD_COMMAND && sasr != WD_DATA && sasr != WD_AUXILIARY_STATUS )
			{
				sasr = ( sasr + 1 ) & 0x1f;
			}

			return ret;
		}

		default:
		{
			logerror( "WD33C93: Read from invalid offset %d\n", offset );
		}
		break;
	}

	return 0;
}

wd33c93_device::wd33c93_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	legacy_scsi_host_adapter(mconfig, WD33C93, tag, owner, clock),
	m_irq_cb(*this)
{
}

void wd33c93_device::device_start()
{
	legacy_scsi_host_adapter::device_start();

	memset(regs, 0, sizeof(regs));
	memset(fifo, 0, sizeof(fifo));
	memset(temp_input, 0, sizeof(temp_input));

	sasr = 0;
	fifo_pos = 0;
	temp_input_pos = 0;
	busphase = 0;
	identify = 0;
	read_pending = 0;

	m_irq_cb.resolve();

	/* allocate a timer for commands */
	cmd_timer = timer_alloc(0);
	service_req_timer = timer_alloc(1);
	deassert_cip_timer = timer_alloc(2);

	save_item( NAME( sasr ) );
	save_item( NAME( regs ) );
	save_item( NAME( fifo ) );
	save_item( NAME( fifo_pos ) );
	save_item( NAME( temp_input ) );
	save_item( NAME( temp_input_pos ) );
	save_item( NAME( busphase ) );
	save_item( NAME( identify ) );
	save_item( NAME( read_pending ) );
}

void wd33c93_device::dma_read_data( int bytes, uint8_t *pData )
{
	int len = bytes;

	if ( len >= get_xfer_count() )
		len = get_xfer_count();

	if ( len == 0 )
		return;

	if ( (temp_input_pos+len) >= TEMP_INPUT_LEN )
	{
		logerror( "Reading past end of buffer, increase TEMP_INPUT_LEN size\n" );
		len = TEMP_INPUT_LEN - len;
	}

	assert(len);

	memcpy( pData, &temp_input[temp_input_pos], len );

	temp_input_pos += len;
	len = get_xfer_count() - len;
	set_xfer_count(len);
}

void wd33c93_device::dma_write_data(int bytes, uint8_t *pData)
{
	write_data(pData, bytes);
}

void wd33c93_device::clear_dma()
{
	/* indicate DMA completed by clearing the transfer count */
	set_xfer_count(0);
	regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR;
}

int wd33c93_device::get_dma_count()
{
	return get_xfer_count();
}

DEFINE_DEVICE_TYPE(WD33C93, wd33c93_device, "wd33c93", "Western Digital WD33C93 SCSI")