summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/machine/315_5296.cpp
blob: b08494dfc8fbcb83115b47004d9d21f5a3f99175 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                       
                                           


                                                                       
 
                                                                        
                                                                           

                                                          











                                                                            

                                                                       
                
                             

 
                                                                                        




                                                   



                                                                                                                             
                            
                            









                                                   


                                            
 



                                        
                                        









                                                   
 




                                                          
                                               
                                        
                        




                                                   
                                                 
 
                       
 




                                                                                                
                                                                 
                                                              
 
                                                          
                                                            
 
















                                                   
 

                              
         
 



                    
                                                             
 
                       






                                                                                               
                                                                    


                                                      
 

                               


                                                                                                    
                                                   
                                                               
 



                                                                                             








                                                                        

                                                                                             
                                                                                                             
                                 
                         
 

                                     
 



                              
// license:BSD-3-Clause
// copyright-holders:hap, Charles MacDonald
/**********************************************************************

    Sega 315-5296 I/O chip

    Sega 100-pin QFP, with 8 bidirectional I/O ports, and 3 output pins.
    It also has chip select(/FMCS) and clock(CKOT) for a peripheral device.
    Commonly used from the late 80s up until Sega Model 2.

    The I/O chip has 64 addresses:
    $00-0F : I/O ports, security, configuration registers
    $10-1F : Unused (no effect when read or written)
    $20-3F : Unused (enables /FMCS output, eg. to YM2151 /CS)

    On System 16 derivatives, the unused locations return the 68000 prefetch
    value off the bus when read.


    TODO:
    - complete emulation of CNT register

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

#include "emu.h"
#include "machine/315_5296.h"


DEFINE_DEVICE_TYPE(SEGA_315_5296, sega_315_5296_device, "315_5296", "Sega 315-5296 I/O")

//-------------------------------------------------
//  sega_315_5296_device - constructor
//-------------------------------------------------

sega_315_5296_device::sega_315_5296_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, SEGA_315_5296, tag, owner, clock),
	m_in_port_cb(*this),
	m_out_port_cb(*this),
	m_out_cnt_cb(*this),
	m_dir_override(0xff)
{
}

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

void sega_315_5296_device::device_start()
{
	// resolve callbacks
	m_in_port_cb.resolve_all_safe(0xff);
	m_out_port_cb.resolve_all_safe();
	m_out_cnt_cb.resolve_all_safe();

	// register for savestates
	save_item(NAME(m_output_latch));
	save_item(NAME(m_cnt));
	save_item(NAME(m_dir));
	save_item(NAME(m_dir_override));
}

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

void sega_315_5296_device::device_reset()
{
	// all ports are set to input
	m_dir = 0;

	// clear output ports
	memset(m_output_latch, 0, sizeof(m_output_latch));
	m_cnt = 0;

	for (int i = 0; i < 8; i++)
		m_out_port_cb[i]((offs_t)i, 0);
	for (auto & elem : m_out_cnt_cb)
		elem(0);
}


//-------------------------------------------------

uint8_t sega_315_5296_device::read(offs_t offset)
{
	offset &= 0x3f;

	switch (offset)
	{
		// port A to H
		case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
			// if the port is configured as an output, return the last thing written
			if (m_dir & m_dir_override & 1 << offset)
				return m_output_latch[offset];

			// otherwise, return an input port
			return m_in_port_cb[offset](offset);

		// 'SEGA' protection
		case 0x8:
			return 'S';
		case 0x9:
			return 'E';
		case 0xa:
			return 'G';
		case 0xb:
			return 'A';

		// CNT register & mirror
		case 0xc: case 0xe:
			return m_cnt;

		// port direction register & mirror
		case 0xd: case 0xf:
			return m_dir;

		default:
			break;
	}

	return 0xff;
}


void sega_315_5296_device::write(offs_t offset, uint8_t data)
{
	offset &= 0x3f;

	switch (offset)
	{
		// port A to H
		case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
			// if the port is configured as an output, write it
			if (m_dir & 1 << offset)
				m_out_port_cb[offset](offset, data);

			m_output_latch[offset] = data;
			break;

		// CNT register
		case 0xe:
			// d0-2: CNT0-2 output pins
			// note: When CNT2 is configured as clock output, bit 2 of this register has
			// no effect on the output level of CNT2.
			for (int i = 0; i < 3; i++)
				m_out_cnt_cb[i](data >> i & 1);

			// d3: CNT2 output mode (1= Clock output, 0= Programmable output)
			// d4,5: CNT2 clock divider (0= CLK/4, 1= CLK/8, 2= CLK/16, 3= CLK/2)
			// d6,7: CKOT clock divider (0= CLK/4, 1= CLK/8, 2= CLK/16, 3= CLK/2)
			// TODO..
			m_cnt = data;
			break;

		// port direction register
		case 0xf:
			// refresh output ports if the direction changed
			for (int i = 0; i < 8; i++)
			{
				if ((m_dir ^ data) & (1 << i))
				{
					logerror("Port %c configured for output\n", 'A' + i);
					m_out_port_cb[i]((offs_t)i, (data & 1 << i) ? m_output_latch[i] : 0);
				}
			}

			m_dir = data;
			break;

		default:
			break;
	}
}