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

                                












                                                                          
                

                            


                      
 
                                                                                              
 
                                                                                             
 
                                    
                                                                      
         
                                      
 

                                                                                               

                                        
                         
                                                                                                                       
                         
                              


                                                      
                                                                                  

                                        
                         
                                                                                                                 
                         
                                          

                               


                                                                                           
         
                          


 
                                                     
 
                                
 


                                      
                                
                                                                                                          
 




                                                                                      



                                       
                                
                 
                                                                                                                      
                 
 

                                     
         
                    

 

                                    
 
                                                                      
         
                                      

                                                      
                                                      

                                        
                         
                                                                                                                    




                                               
 



                                              
 
                                    
 

                                                                                
                                                         





                                                                  
                                                         



                                                            
                                                                 
                                                                                                                                     
                                 
                         




                 
 
                                            
 
                             
 
 
 

                                    





                                                                   
                                            

                                                  
                                                     
                                 

                                                                                                      
                                         
                                                                                    




                                                                          
                                                      


                                 
                         
                                                        

                                       
                                                     

                                              
                                                              




                                                    



                                               
                                     





                              
                                      
 






                                                                                   
                                 
                                                                                                                         











                                                                             
                         
                                                        




                                                          
                                         
                                                                                                                                 
                                         
 
                                                      







                                                               
                                         
                                                                                                                                 
                                         



                                                            
                                                                   

                                                              
                                                                                                                               
                                                         
                                                                                 
                                                                 
                                                                                       






                                                                              
                                                                          
                                                         
                                                                               


                                                              
                                                                                  

                                                              
                                                                                                                               
                                                         
                                                                                  
                                                                 

                                                                                                  




                                                                              
                                                                             

                                                              
                                                                          
                                                         
                                                                               
                                                                                     







                                                              
                                       






                                                        
                                         
                                                                                                                                 
                                         
 





                                                                     
                                            


                                                                                                   




                                                        
                                         
                                                                                                                                 
                                         
 

                                                                                           




                                                        
                                         
                                                                                                                                 
                                         
 




                                                                           




                                                                                      


                                                                                                               
 

                                                                                                                           


                                              
         
                    


 


                                                   
 
                                   
 
                            


                                        






















                                            

 
 



























                                                   
 
 

                                                            
                                                                                                             
                                                                                        


                                      


                              

 
// license:BSD-3-Clause
// copyright-holders:Wilbert Pol
/**********************************************************************

    8259 PIC interface and emulation

    The 8259 is a programmable interrupt controller used to multiplex
    interrupts for x86 and other computers.  The chip is set up by
    writing a series of Initialization Command Words (ICWs) after which
    the chip is operational and capable of dispatching interrupts.  After
    this, Operation Command Words (OCWs) can be written to control further
    behavior.

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

#include "emu.h"
#include "machine/pic8259.h"

#define LOG_ICW     0
#define LOG_OCW     0
#define LOG_GENERAL  0

ALLOW_SAVE_TYPE(pic8259_device::pic8259_state_t); // allow save_item on a non-fundamental type

void pic8259_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	/* check the various IRQs */
	for (int n = 0, irq = m_prio; n < 8; n++, irq = (irq + 1) & 7)
	{
		UINT8 mask = 1 << irq;

		/* is this IRQ in service and not cascading and sfnm? */
		if ((m_isr & mask) && !(m_master && m_cascade && m_nested && (m_slave & mask)))
		{
			if (LOG_GENERAL)
			{
				logerror("pic8259_timerproc() %s: PIC IRQ #%d still in service\n", tag().c_str(), irq);
			}
			break;
		}

		/* is this IRQ pending and enabled? */
		if ((m_state == STATE_READY) && (m_irr & mask) && !(m_imr & mask))
		{
			if (LOG_GENERAL)
			{
				logerror("pic8259_timerproc() %s: PIC triggering IRQ #%d\n", tag().c_str(), irq);
			}
			m_out_int_func(1);
			return;
		}
		// if sfnm and in-service don't continue
		if((m_isr & mask) && m_master && m_cascade && m_nested && (m_slave & mask))
			break;
	}
	m_out_int_func(0);
}


void pic8259_device::set_irq_line(int irq, int state)
{
	UINT8 mask = (1 << irq);

	if (state)
	{
		/* setting IRQ line */
		if (LOG_GENERAL)
			logerror("pic8259_set_irq_line() %s: PIC set IRQ line #%d\n", tag().c_str(), irq);

		if(m_level_trig_mode || (!m_level_trig_mode && !(m_irq_lines & mask)))
		{
			m_irr |= mask;
		}
		m_irq_lines |= mask;
	}
	else
	{
		/* clearing IRQ line */
		if (LOG_GENERAL)
		{
			logerror("pic8259_device::set_irq_line() %s: PIC cleared IRQ line #%d\n", tag().c_str(), irq);
		}

		m_irq_lines &= ~mask;
		m_irr &= ~mask;
	}
	set_timer();
}


UINT32 pic8259_device::acknowledge()
{
	for (int n = 0, irq = m_prio; n < 8; n++, irq = (irq + 1) & 7)
	{
		UINT8 mask = 1 << irq;

		/* is this IRQ pending and enabled? */
		if ((m_irr & mask) && !(m_imr & mask))
		{
			if (LOG_GENERAL)
			{
				logerror("pic8259_acknowledge() %s: PIC acknowledge IRQ #%d\n", tag().c_str(), irq);
			}
			if (!m_level_trig_mode)
			{
				m_irr &= ~mask;
			}

			if (!m_auto_eoi)
			{
				m_isr |= mask;
			}

			set_timer();

			if ((m_cascade!=0) && (m_master!=0) && (mask & m_slave))
			{
				// it's from slave device
				return m_read_slave_ack_func(irq);
			}
			else
			{
				if (m_is_x86)
				{
					/* For x86 mode*/
					return irq + m_base;
				}
				else
				{
					/* in case of 8080/85) */
					return 0xcd0000 + (m_vector_addr_high << 8) + m_vector_addr_low + (irq << (3-m_vector_size));
				}
			}
		}
	}
	return 0;
}


IRQ_CALLBACK_MEMBER(pic8259_device::inta_cb)
{
	return acknowledge();
}


READ8_MEMBER( pic8259_device::read )
{
	/* NPW 18-May-2003 - Changing 0xFF to 0x00 as per Ruslan */
	UINT8 data = 0x00;

	switch(offset)
	{
		case 0: /* PIC acknowledge IRQ */
			if ( m_ocw3 & 0x04 )
			{
				/* Polling mode */
				if ( m_irr & ~m_imr )
				{
					/* check the various IRQs */
					for (int n = 0, irq = m_prio; n < 8; n++, irq = (irq + 1) & 7)
					{
						if ( ( 1 << irq ) & m_irr & ~m_imr )
						{
							data = 0x80 | irq;
							break;
						}
					}
					acknowledge();
				}
			}
			else
			{
				switch ( m_ocw3 & 0x03 )
				{
				case 2:
					data = m_irr;
					break;
				case 3:
					data = m_isr & ~m_imr;
					break;
				default:
					data = 0x00;
					break;
				}
			}
			break;

		case 1: /* PIC mask register */
			data = m_imr;
			break;
	}
	return data;
}


WRITE8_MEMBER( pic8259_device::write )
{
	switch(offset)
	{
		case 0:    /* PIC acknowledge IRQ */
			if (data & 0x10)
			{
				/* write ICW1 - this pretty much resets the chip */
				if (LOG_ICW)
				{
					logerror("pic8259_device::write() %s: ICW1; data=0x%02X\n", tag().c_str(), data);
				}

				m_imr                = 0x00;
				m_isr                = 0x00;
				m_irr                = 0x00;
				m_level_trig_mode    = (data & 0x08) ? 1 : 0;
				m_vector_size        = (data & 0x04) ? 1 : 0;
				m_cascade            = (data & 0x02) ? 0 : 1;
				m_icw4_needed        = (data & 0x01) ? 1 : 0;
				m_vector_addr_low    = (data & 0xe0);
				m_state          = STATE_ICW2;
				m_out_int_func(0);
			}
			else if (m_state == STATE_READY)
			{
				if ((data & 0x98) == 0x08)
				{
					/* write OCW3 */
					if (LOG_OCW)
					{
						logerror("pic8259_device::write() %s: OCW3; data=0x%02X\n", tag().c_str(), data);
					}

					m_ocw3 = data;
				}
				else if ((data & 0x18) == 0x00)
				{
					int n = data & 7;
					UINT8 mask = 1 << n;

					/* write OCW2 */
					if (LOG_OCW)
					{
						logerror("pic8259_device::write() %s: OCW2; data=0x%02X\n", tag().c_str(), data);
					}

					switch (data & 0xe0)
					{
						case 0x00:
							m_prio = 0;
							break;
						case 0x20:
							for (n = 0, mask = 1<<m_prio; n < 8; n++, mask = (mask<<1) | (mask>>7))
							{
								if (m_isr & mask)
								{
									m_isr &= ~mask;
									break;
								}
							}
							break;
						case 0x40:
							break;
						case 0x60:
							if( m_isr & mask )
							{
								m_isr &= ~mask;
							}
							break;
						case 0x80:
							m_prio = (m_prio + 1) & 7;
							break;
						case 0xa0:
							for (n = 0, mask = 1<<m_prio; n < 8; n++, mask = (mask<<1) | (mask>>7))
							{
								if( m_isr & mask )
								{
									m_isr &= ~mask;
									m_prio = (m_prio + 1) & 7;
									break;
								}
							}
							break;
						case 0xc0:
							m_prio = (n + 1) & 7;
							break;
						case 0xe0:
							if( m_isr & mask )
							{
								m_isr &= ~mask;
								m_prio = (n + 1) & 7;
							}
							break;
					}
				}
			}
			break;

		case 1:
			switch(m_state)
			{
				case STATE_ICW1:
					break;

				case STATE_ICW2:
					/* write ICW2 */
					if (LOG_ICW)
					{
						logerror("pic8259_device::write() %s: ICW2; data=0x%02X\n", tag().c_str(), data);
					}

					m_base = data & 0xf8;
					m_vector_addr_high = data ;
					if (m_cascade)
					{
						m_state = STATE_ICW3;
					}
					else
					{
						m_state = m_icw4_needed ? STATE_ICW4 : STATE_READY;
					}
					break;

				case STATE_ICW3:
					/* write ICW3 */
					if (LOG_ICW)
					{
						logerror("pic8259_device::write() %s: ICW3; data=0x%02X\n", tag().c_str(), data);
					}

					m_slave = data;
					m_state = m_icw4_needed ? STATE_ICW4 : STATE_READY;
					break;

				case STATE_ICW4:
					/* write ICW4 */
					if (LOG_ICW)
					{
						logerror("pic8259_device::write() %s: ICW4; data=0x%02X\n", tag().c_str(), data);
					}

					m_nested = (data & 0x10) ? 1 : 0;
					m_mode = (data >> 2) & 3;
					m_auto_eoi = (data & 0x02) ? 1 : 0;
					m_is_x86 = (data & 0x01) ? 1 : 0;
					m_state = STATE_READY;
					break;

				case STATE_READY:
					/* write OCW1 - set interrupt mask register */
					if (LOG_OCW)
					{
						logerror("pic8259_device::write(): OCW1; data=0x%02X\n", data);
					}

					//printf("%s %02x\n",m_master ? "master pic8259 mask" : "slave pic8259 mask",data);
					m_imr = data;
					break;
			}
			break;
	}
	set_timer();
}


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

void pic8259_device::device_start()
{
	// resolve callbacks
	m_out_int_func.resolve();
	m_sp_en_func.resolve();
	m_read_slave_ack_func.resolve();

	// Register save state items
	save_item(NAME(m_state));
	save_item(NAME(m_isr));
	save_item(NAME(m_irr));
	save_item(NAME(m_prio));
	save_item(NAME(m_imr));
	save_item(NAME(m_irq_lines));
	save_item(NAME(m_input));
	save_item(NAME(m_ocw3));
	save_item(NAME(m_master));
	save_item(NAME(m_level_trig_mode));
	save_item(NAME(m_vector_size));
	save_item(NAME(m_cascade));
	save_item(NAME(m_icw4_needed));
	save_item(NAME(m_vector_addr_low));
	save_item(NAME(m_base));
	save_item(NAME(m_vector_addr_high));
	save_item(NAME(m_slave));
	save_item(NAME(m_nested));
	save_item(NAME(m_mode));
	save_item(NAME(m_auto_eoi));
	save_item(NAME(m_is_x86));
}


//-------------------------------------------------
//  device_reset - device-specific reset
//-------------------------------------------------

void pic8259_device::device_reset()
{
	m_state = STATE_READY;
	m_isr = 0;
	m_irr = 0;
	m_irq_lines = 0;
	m_prio = 0;
	m_imr = 0;
	m_input = 0;
	m_ocw3 = 2;
	m_level_trig_mode = 0;
	m_vector_size = 0;
	m_cascade = 0;
	m_icw4_needed = 0;
	m_base = 0;
	m_slave = 0;
	m_nested = 0;
	m_mode = 0;
	m_auto_eoi = 0;
	m_is_x86 = 0;
	m_vector_addr_low = 0;
	m_vector_addr_high = 0;

	m_master = m_sp_en_func();
}

const device_type PIC8259 = &device_creator<pic8259_device>;

pic8259_device::pic8259_device(const machine_config &mconfig, std::string tag, device_t *owner, UINT32 clock)
	: device_t(mconfig, PIC8259, "8259 PIC", tag, owner, clock, "pit8259", __FILE__)
	, m_out_int_func(*this)
	, m_sp_en_func(*this)
	, m_read_slave_ack_func(*this)
	, m_irr(0)
	, m_irq_lines(0)
	, m_level_trig_mode(0)
{
}