summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/video/huc6202.cpp
blob: 42ffaafef1451427ce78e183b917ac48de1ce6c2 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                






                                                                       

                    

                    
 
                                                                            

 
                                                                                                               













                                                                                    



 
                                
 
                                                           
 

                                              
























                                                                                                   
                                                                 
 
                                                                                                    
                 
                                                                                                            
                         
                                                                         
                                 
                                                                                


                                                                                   
                                                                                
















                                                                                           
                                                                              



                                                                      



























                                                                                                      
                                                    











                                                              
                                                                                                            









                                              
                                           
 

                                                                    
 
                                                                    




                                                  

                                      




                                                  

                                      


 
                                      
 
                            


                             
                                                      







                                                                       
                                                      
                                                             






                                                                       
                                              


                                                
                                              


                                                         
                                              


                                                
                                              







                                                         
                                                  


                             
                                                      







                                                                   
                                                      







                                                                   
                                              



                                                                  
                                              



                                                                                       
                                              



                                                                  
                                              



                                                                                       
                                            





                                                  
                                         


                          
                                             


            
                                             



         
                                                     


                          
                                             


            
                                             






                                   












                                             

                                                      











                                                        









































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

    Hudson/NEC HuC6202 Video Priority Controller

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

#include "emu.h"
#include "huc6202.h"

#include "huc6270.h"


DEFINE_DEVICE_TYPE(HUC6202, huc6202_device, "huc6202", "Hudson HuC6202 VPC")


huc6202_device::huc6202_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, HUC6202, tag, owner, clock)
	, m_next_pixel_0_cb(*this)
	, m_time_til_next_event_0_cb(*this)
	, m_vsync_changed_0_cb(*this)
	, m_hsync_changed_0_cb(*this)
	, m_read_0_cb(*this)
	, m_write_0_cb(*this)
	, m_next_pixel_1_cb(*this)
	, m_time_til_next_event_1_cb(*this)
	, m_vsync_changed_1_cb(*this)
	, m_hsync_changed_1_cb(*this)
	, m_read_1_cb(*this)
	, m_write_1_cb(*this)
	, m_window1(0), m_window2(0), m_io_device(0), m_map_index(0), m_map_dirty(0)
{
}


u16 huc6202_device::next_pixel()
{
	uint16_t data = huc6270_device::HUC6270_BACKGROUND;

	uint16_t data_0 = m_next_pixel_0_cb();
	uint16_t data_1 = m_next_pixel_1_cb();

	if ( data_0 == huc6270_device::HUC6270_SPRITE && data_1 == huc6270_device::HUC6270_SPRITE )
	{
		m_map_index = 0;
		if ( m_map_dirty )
		{
			int i;

			for ( i = 0; i < 512; i++ )
			{
				m_prio_map[ i ] = 0;
				if ( m_window1 < 0x40 || i > m_window1 )
				{
					m_prio_map [ i ] |= 1;
				}
				if ( m_window2 < 0x40 || i > m_window2 )
				{
					m_prio_map[ i ] |= 2;
				}
			}
			m_map_dirty = 0;
		}
	}
	else
	{
		uint8_t   prio_index = m_prio_map[ m_map_index ];

		if ( m_prio[ prio_index ].dev0_enabled && data_0 != huc6270_device::HUC6270_SPRITE )
		{
			if ( m_prio[ prio_index ].dev1_enabled && data_1 != huc6270_device::HUC6270_SPRITE )
			{
				switch ( m_prio[ prio_index ].prio_type )
				{
				case 0:     /* Back - BG1 SP1 BG0 SP0 - Front */
					data = ( data_0 & 0x0F ) ? data_0 : data_1;
					break;

				case 1:     /* Back - BG1 BG0 SP1 SP0 - Front */
					if ( data_0 > huc6270_device::HUC6270_SPRITE )
					{
						/* Device 0 sprite */
						data = data_0;
					}
					else if ( data_1 > huc6270_device::HUC6270_SPRITE )
					{
						/* Device 1 sprite */
						data = data_1;
					}
					else
					{
						/* Device 0 and 1 backgrounds */
						data = ( data_0 & 0x0F ) ? data_0 : data_1;
					}
					break;

				case 2:     /* Back - BG0 + SP1 => BG0 - Front
				                      BG0 + BG1 => BG0
				                      BG1 + SP0 => BG1
				                      SP0 + SP1 => SP0
				            */
					if ( data_1 > huc6270_device::HUC6270_SPRITE )
					{
						if ( data_0 > huc6270_device::HUC6270_SPRITE )
						{
							/* Device 1 sprite, device 0 sprite */
							data = data_0;
						}
						else
						{
							/* Device 1 sprite, device 0 background */
							data = ( data_0 & 0x0F ) ? data_0 : data_1;
						}
					}
					else
					{
						if ( data_0 > huc6270_device::HUC6270_SPRITE )
						{
							/* Device 1 background, device 0 sprite */
							data = data_1;
						}
						else
						{
							/* Device 1 background, device 0 background */
							data = ( data_0 & 0x0F ) ? data_0 : data_1;
						}
					}
					break;

				case 3:     /* ?? */
					break;
				}
			}
			else
			{
				/* Only device 0 is enabled */
				data = data_0;
			}
		}
		else
		{
			/* Only device 1 is enabled */
			if ( m_prio[ prio_index ].dev1_enabled && data_1 != huc6270_device::HUC6270_SPRITE )
			{
				data = data_1;
			}
		}
		m_map_index += 1;
	}
	return data;
}


u16 huc6202_device::time_until_next_event()
{
	uint16_t next_event_clocks_0 = m_time_til_next_event_0_cb();
	uint16_t next_event_clocks_1 = m_time_til_next_event_1_cb();

	return std::min( next_event_clocks_0, next_event_clocks_1 );
}


WRITE_LINE_MEMBER( huc6202_device::vsync_changed )
{
	m_vsync_changed_0_cb( state );
	m_vsync_changed_1_cb( state );
}


WRITE_LINE_MEMBER( huc6202_device::hsync_changed )
{
	m_hsync_changed_0_cb( state );
	m_hsync_changed_1_cb( state );
}


u8 huc6202_device::read(offs_t offset)
{
	uint8_t data = 0xFF;

	switch ( offset & 7 )
	{
		case 0x00:  /* Priority register #0 */
			data = ( m_prio[0].prio_type << 2 ) |
				( m_prio[0].dev0_enabled ? 0x01 : 0 ) |
				( m_prio[0].dev1_enabled ? 0x02 : 0 ) |
				( m_prio[1].prio_type << 6 ) |
				( m_prio[1].dev0_enabled ? 0x10 : 0 ) |
				( m_prio[1].dev1_enabled ? 0x20 : 0 );
			break;

		case 0x01:  /* Priority register #1 */
			data = ( m_prio[2].prio_type << 2 ) |
				( m_prio[2].dev0_enabled ? 0x01 : 0 ) |
				( m_prio[2].dev1_enabled ? 0x02 : 0 ) |
				( m_prio[3].prio_type << 6 ) |
				( m_prio[3].dev0_enabled ? 0x10 : 0 ) |
				( m_prio[3].dev1_enabled ? 0x20 : 0 );
			break;

		case 0x02:  /* Window 1 LSB */
			data = m_window1 & 0xFF;
			break;

		case 0x03:  /* Window 1 MSB */
			data = ( m_window1 >> 8 ) & 0xFF;
			break;

		case 0x04:  /* Window 2 LSB */
			data = m_window2 & 0xFF;
			break;

		case 0x05:  /* Window 2 MSB */
			data = ( m_window2 >> 8 ) & 0xFF;
			break;
	}

	return data;
}


void huc6202_device::write(offs_t offset, u8 data)
{
	switch ( offset & 7 )
	{
		case 0x00:  /* Priority register #0 */
			m_prio[0].dev0_enabled = data & 0x01;
			m_prio[0].dev1_enabled = data & 0x02;
			m_prio[0].prio_type = ( data >> 2 ) & 0x03;
			m_prio[1].dev0_enabled = data & 0x10;
			m_prio[1].dev1_enabled = data & 0x20;
			m_prio[1].prio_type = ( data >> 6 ) & 0x03;
			break;

		case 0x01:  /* Priority register #1 */
			m_prio[2].dev0_enabled = data & 0x01;
			m_prio[2].dev1_enabled = data & 0x02;
			m_prio[2].prio_type = ( data >> 2 ) & 0x03;
			m_prio[3].dev0_enabled = data & 0x10;
			m_prio[3].dev1_enabled = data & 0x20;
			m_prio[3].prio_type = ( data >> 6 ) & 0x03;
			break;

		case 0x02:  /* Window 1 LSB */
			m_window1 = ( m_window1 & 0xFF00 ) | data;
			m_map_dirty = 1;
			break;

		case 0x03:  /* Window 1 MSB */
			m_window1 = ( ( m_window1 & 0x00FF ) | ( data << 8 ) ) & 0x3FF;
			m_map_dirty = 1;
			break;

		case 0x04:  /* Window 2 LSB */
			m_window2 = ( m_window2 & 0xFF00 ) | data;
			m_map_dirty = 1;
			break;

		case 0x05:  /* Window 2 MSB */
			m_window2 = ( ( m_window2 & 0x00FF ) | ( data << 8 ) ) & 0x3FF;
			m_map_dirty = 1;
			break;

		case 0x06:  /* I/O select */
			m_io_device = data & 0x01;
			break;
	}
}


u8 huc6202_device::io_read(offs_t offset)
{
	if ( m_io_device )
	{
		return m_read_1_cb( offset );
	}
	else
	{
		return m_read_0_cb( offset );
	}
}


void huc6202_device::io_write(offs_t offset, u8 data)
{
	if ( m_io_device )
	{
		m_write_1_cb( offset, data );
	}
	else
	{
		m_write_0_cb( offset, data );
	}
}


void huc6202_device::device_start()
{
	/* Resolve callbacks */
	m_next_pixel_0_cb.resolve();
	m_time_til_next_event_0_cb.resolve();
	m_hsync_changed_0_cb.resolve();
	m_vsync_changed_0_cb.resolve();
	m_read_0_cb.resolve();
	m_write_0_cb.resolve();

	m_next_pixel_1_cb.resolve();
	m_time_til_next_event_1_cb.resolve();
	m_hsync_changed_1_cb.resolve();
	m_vsync_changed_1_cb.resolve();
	m_read_1_cb.resolve();
	m_write_1_cb.resolve();

	/* We want all our callbacks to be resolved */
	assert( ! m_next_pixel_0_cb.isnull() );
	assert( ! m_time_til_next_event_0_cb.isnull() );
	assert( ! m_hsync_changed_0_cb.isnull() );
	assert( ! m_vsync_changed_0_cb.isnull() );
	assert( ! m_read_0_cb.isnull() );
	assert( ! m_write_0_cb.isnull() );
	assert( ! m_next_pixel_1_cb.isnull() );
	assert( ! m_time_til_next_event_1_cb.isnull() );
	assert( ! m_hsync_changed_1_cb.isnull() );
	assert( ! m_vsync_changed_1_cb.isnull() );
	assert( ! m_read_1_cb.isnull() );
	assert( ! m_write_1_cb.isnull() );

	/* Register save items */
	save_item(NAME(m_prio[0].prio_type));
	save_item(NAME(m_prio[0].dev0_enabled));
	save_item(NAME(m_prio[0].dev1_enabled));
	save_item(NAME(m_prio[1].prio_type));
	save_item(NAME(m_prio[1].dev0_enabled));
	save_item(NAME(m_prio[1].dev1_enabled));
	save_item(NAME(m_prio[2].prio_type));
	save_item(NAME(m_prio[2].dev0_enabled));
	save_item(NAME(m_prio[2].dev1_enabled));
	save_item(NAME(m_prio[3].prio_type));
	save_item(NAME(m_prio[3].dev0_enabled));
	save_item(NAME(m_prio[3].dev1_enabled));
	save_item(NAME(m_window1));
	save_item(NAME(m_window2));
	save_item(NAME(m_io_device));
	save_item(NAME(m_map_index));
	save_item(NAME(m_map_dirty));
	save_item(NAME(m_prio_map));
}


void huc6202_device::device_reset()
{
	m_prio[0].prio_type = 0;
	m_prio[0].dev0_enabled = 1;
	m_prio[0].dev1_enabled = 0;
	m_prio[1].prio_type = 0;
	m_prio[1].dev0_enabled = 1;
	m_prio[1].dev1_enabled = 0;
	m_prio[2].prio_type = 0;
	m_prio[2].dev0_enabled = 1;
	m_prio[2].dev1_enabled = 0;
	m_prio[3].prio_type = 0;
	m_prio[3].dev0_enabled = 1;
	m_prio[3].dev1_enabled = 0;
	m_map_dirty = 1;
	m_window1 = 0;
	m_window2 = 0;
	m_io_device = 0;
}