summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/video/huc6270.cpp
blob: 09f49963ba90d7cf2bafb2286efb033c8fa7526a (plain) (tree)
1
2

                                















































                                                                            
                                                           



                                                                       

                    


                     





















                    

                                         
 

                                     






                                                                                               

 
                                                                            

 
                                                     
 
                                                                                                               


                                                       




  
                                          


                                                





                                                                                                    

                    
                                      
         
                                                                                                       




















                                                                                                                              
                                        































                                                                                                                  
                                                                                                     






































































































                                                                                                                                            
                                                        











                                               
                                                        


                                                                

                                                    



                                                          
                                                                        













                                                                                                    
                                                    











                                             

                                            


                                                             

                                            




                                                     

                                            



                                                

                                            









                                                    
                          
                                      
                                            


                                                                         
                                   










                                                                                                  

                                            


                                                             

                                            


                                                    

                                            
                                                                            












                                                                          
                                
 
                                       

                                                      
                                           

                                                           
                                                   
                 
                                                                                          








































                                                                                                 
                                                                















                                           
                                                    
   
                                           







                                                  

                                                          
                 
                                                    





                                                   
                 

                                                                                           
                                        










                                                  
                            
         

                                                          
                 
                                               
                         






                                                                        
                         
 








                                                                                
 
                                          
 

                                                   
 
                                     

                    
                 





                                                                         
                         





                        










                                                                                                  
 

                                      
 
                                                                      

                                                        

                                         
 

                                                        












                                                        
 
                                      
 
                            


                             
                                        

                                                                                                                     
                                                       










                                                                                
 

                                                                 





                                                                                                                    






                              
                                                  
 
                                                                                           


                             
                                                     


                                                       
                                              

                                                   
                                                                                       


                                                                            
                                                                                      
                                                                            

                                                                         





                                                                                                                             

                                              
                                                                         


                                                                          
                                                                          


                                                                        
                                                                                 
                                                                          


                                                                 
                                                        
                     

                                              
                                                                                      
                                                                          

                                              
                                                                                      

                                                                          

                                              
                                                                               


                                                                          
                                                                                  


                                                                          
                                                                                     


                                                                          
                                                                                


                                                                          
                                                                                   


                                                                          
                                                                                                


                                                                          
                                                                              


                                                                          
                                                                                     


                                                                            
                                                                                          


                                                                            
                                                                             


                                                                            
                                                                                





                                                                              
                                              

                                                   
                                                                                       


                                                                                     
                                                                                      
                                                                                     



                                                                         

                                              
                                                                         
                                                                                   
                                                                                              

                                                                         


                                                                                        
                                                                          


                                                                                 
                                                                                 
                                                                                              
                                                                               


                                                                 
                                                        
                     

                                              
                                                                                      


                                                                                              
                                                                                      



                                                                                              
                                                                               


                                                                                   
                                                                                  


                                                                                   
                                                                                     


                                                                                   
                                                                                


                                                                                   
                                                                                   


                                                                                   
                                                                                                


                                                                                   
                                                                              


                                                                                   
                                                                                     


                                                                                     
                                                                                          


                                                                                     
                                                                             




                                                                                     
                                                                                





                                                                                       
                  





                                   
                                        
 
                                                                             
                                             
 
                                                                 












































                                             













                                   
                                                                          
                       
                                                                        










                                
                         
                                    

                         
                                    


                          
                          

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

    NEC HuC6270 Video Display Controller

    The HuC6270 basically outputs a 9-bit stream of pixel data which
    holds a color index, a palette index, and an indication whether
    the pixel contains background data or from sprite data.

    This data can be used by a colour encoder to output graphics.

    A regular screen is displayed as follows:

        |<- HDS ->|<--       HDW       -->|<- HDE ->|<- HSW ->|
        |---------|-----------------------|---------|---------|
    VSW |                                                     |
        |---------|-----------------------|---------|---------|
    VDS |                                                     |
        |                  overscan                           |
        |---------|-----------------------|---------|---------|
        |         |                       |                   |
        |         |                       |                   |
        |         |                       |                   |
        |         |                       |                   |
    VDW | overscan|    active display     |      overscan     |
        |         |                       |                   |
        |         |                       |                   |
        |         |                       |                   |
        |         |                       |                   |
        |---------|-----------------------|---------|---------|
    VCR |                  overscan                           |
        |                                                     |
        |---------|-----------------------|---------|---------|
        ^end hsync
         ^start vsync (30 cycles after hsync)


KNOWN ISSUES
  - Violent Soldier (probably connected):
    - In the intro some artefacts appear at the top of the
      screen every now and then.
  - In ccovell's splitres test not all sections seem to be aligned properly.
  - Side Arms: Seems to be totally broken.


TODO
  - Fix timing of VRAM-SATB DMA
  - Implement VRAM-VRAM DMA
  - DMA speeds differ depending on the dot clock selected in the huc6270
  - Convert VRAM bus to actual space address (optimization)

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

#include "emu.h"
#include "huc6270.h"

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


enum {
	MAWR = 0x00,
	MARR = 0x01,
	VxR = 0x02,
	CR = 0x05,
	RCR = 0x06,
	BXR = 0x07,
	BYR = 0x08,
	MWR = 0x09,
	HSR = 0x0A,
	HDR = 0x0B,
	VPR = 0x0C,
	VDW = 0x0D,
	VCR = 0x0E,
	DCR = 0x0F,
	SOUR = 0x10,
	DESR = 0x11,
	LENR = 0x12,
	DVSSR = 0x13
};

ALLOW_SAVE_TYPE(huc6270_device::v_state);
ALLOW_SAVE_TYPE(huc6270_device::h_state);


/* Bits in the VDC status register */
#define HUC6270_BSY         0x40    /* Set when the VDC accesses VRAM */
#define HUC6270_VD          0x20    /* Set when in the vertical blanking period */
#define HUC6270_DV          0x10    /* Set when a VRAM > VRAM DMA transfer is done */
#define HUC6270_DS          0x08    /* Set when a VRAM > SATB DMA transfer is done */
#define HUC6270_RR          0x04    /* Set when the current scanline equals the RCR register */
#define HUC6270_OR          0x02    /* Set when there are more than 16 sprites on a line */
#define HUC6270_CR          0x01    /* Set when sprite #0 overlaps with another sprite */


DEFINE_DEVICE_TYPE(HUC6270, huc6270_device, "huc6270", "Hudson HuC6270 VDC")


constexpr uint8_t huc6270_device::vram_increments[4];

huc6270_device::huc6270_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, HUC6270, tag, owner, clock)
	, m_vram_size(0)
	, m_irq_changed_cb(*this)
{
}


/*
  Read one row of tile data from video ram
*/
inline void huc6270_device::fetch_bat_tile_row()
{
	const uint16_t bat_data = m_vram[ m_bat_address & m_vram_mask ];
	const uint16_t tile_palette = ( bat_data >> 8 ) & 0xF0;
	uint16_t data1 = m_vram[ ( ( ( bat_data & 0x0FFF ) << 4 ) + m_bat_row + 0 ) & m_vram_mask ];
	uint16_t data2 = ( data1 >> 7 ) & 0x1FE;
	uint16_t data3 = m_vram[ ( ( ( bat_data & 0x0FFF ) << 4 ) + m_bat_row + 8 ) & m_vram_mask ];
	uint16_t data4 = ( data3 >> 5 ) & 0x7F8;
	data3 <<= 2;

	for ( int i = 7; i >= 0; i-- )
	{
		uint16_t c = ( data1 & 0x01 ) | ( data2 & 0x02 ) | ( data3 & 0x04 ) | ( data4 & 0x08 );

		/* Colour 0 for background tiles is always taken from palette 0 */
		if ( c )
			c |= tile_palette;

		m_bat_tile_row[i] = c;

		data1 >>= 1;
		data2 >>= 1;
		data3 >>= 1;
		data4 >>= 1;
	}
}


void huc6270_device::add_sprite( int index, int x, int pattern, int line, int flip_x, int palette, int priority, int sat_lsb )
{
	int i = m_sprites_this_line;

	if ( i < 16 )
	{
		uint32_t b0, b1, b2, b3;
		int j;

		if ( flip_x )
			flip_x = 0x0F;

		pattern += ( ( line >> 4 ) << 1 );

		if ( ( m_mwr & 0x0c ) == 0x04 )
		{
			if ( ! sat_lsb )
			{
				b0 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x00 ) & m_vram_mask ];
				b1 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x10 ) & m_vram_mask ] << 1;
			}
			else
			{
				b0 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x20 ) & m_vram_mask ];
				b1 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x30 ) & m_vram_mask ] << 1;
			}
			b2 = 0;
			b3 = 0;
		}
		else
		{
			b0 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x00 ) & m_vram_mask ];
			b1 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x10 ) & m_vram_mask ] << 1;
			b2 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x20 ) & m_vram_mask ] << 2;
			b3 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x30 ) & m_vram_mask ] << 3;
		}

		for ( j = 15; j >= 0; j-- )
		{
			uint8_t data = ( b3 & 0x08 ) | ( b2 & 0x04 ) | ( b1 & 0x02 ) | ( b0 & 0x01 );

			if ( data )
			{
				data |= palette << 4;

				if ( x + ( j ^ flip_x ) < 1024 )
				{
					if (! m_sprite_row[ x + ( j ^ flip_x ) ] )
					{
						m_sprite_row[ x + ( j ^ flip_x ) ] = ( priority ? 0x4000 : 0x0000 ) | ( index << 8 ) | data;
					}
					else
					{
						if ( ! ( m_sprite_row[ x + ( j ^ flip_x ) ] & 0xFF00 ) )
						{
							/* Sprite 0 collission */
							m_sprite_row[ x + ( j ^ flip_x ) ] |= 0x8000;
						}
					}
				}
			}

			b0 >>= 1;
			b1 >>= 1;
			b2 >>= 1;
			b3 >>= 1;
		}

		m_sprites_this_line += 1;
	}
}


void huc6270_device::select_sprites()
{
	int i;

	m_sprites_this_line = 0;
	memset( m_sprite_row, 0, sizeof( m_sprite_row ) );
	m_sprite_row_index = 0x20;

	for ( i = 0; i < 4 * 64; i += 4 )
	{
		static const int cgy_table[4] = { 16, 32, 64, 64 };
		int cgy = ( m_sat[i+3] >> 12 ) & 0x03;
		int height = cgy_table[ cgy ];
		int sprite_line = m_raster_count - m_sat[i];

		if ( sprite_line >= 0 && sprite_line < height )
		{
			int pattern = m_sat[i+2] >> 1;
			int sat_lsb = m_sat[i+2] & 0x01;
			int palette = m_sat[i+3] & 0x0F;
			int priority = m_sat[i+3] & 0x80;
			int cgx = m_sat[i+3] & 0x0100;

			/* If CGY is set to 1, bit 1 of the sprite pattern index is forced to 0 */
			if ( cgy & 1 )
				pattern &= ~0x0002;

			/* If CGY is set to 2 or 3, bits 1 and 2 of the sprite pattern index are forced to 0 */
			if ( cgy & 2 )
				pattern &= ~0x0006;

			/* Recalculate line index when sprite is flipped vertically */
			if ( m_sat[i+3] & 0x8000 )
				sprite_line = ( height - 1 ) - sprite_line;

			/* Is the sprite 32 pixels wide */
			if ( cgx )
			{
				/* If CGX is set, bit 0 of the sprite pattern index is forced to 0 */
				pattern &= ~0x0001;

				/* Check for horizontal flip */
				if ( m_sat[i+3] & 0x0800 )
				{
					/* Add to our list of sprites for this line */
					add_sprite( i/4, m_sat[i+1], pattern + 1, sprite_line, 1, palette, priority, sat_lsb );
					add_sprite( i/4, m_sat[i+1] + 16, pattern, sprite_line, 1, palette, priority, sat_lsb );
				}
				else
				{
					/* Add to our list of sprites for this line */
					add_sprite( i/4, m_sat[i+1], pattern, sprite_line, 0, palette, priority, sat_lsb );
					add_sprite( i/4, m_sat[i+1] + 16, pattern + 1, sprite_line, 0, palette, priority, sat_lsb );
				}
			}
			else
			{
				/* Add to our list of sprites for this line */
				add_sprite( i/4, m_sat[i+1], pattern, sprite_line, m_sat[i+3] & 0x0800, palette, priority, sat_lsb );
			}
		}
	}

	/* Check for sprite overflow */
	if ( m_sprites_this_line >= 16 )
	{
		/* note: flag is set only if irq is taken, Mizubaku Daibouken relies on this behaviour */
		if ( m_cr & 0x02 )
		{
			m_status |= HUC6270_OR;
			m_irq_changed_cb( ASSERT_LINE );
		}
	}
}


inline void huc6270_device::handle_vblank()
{
	if ( ! m_vd_triggered )
	{
		if ( m_cr & 0x08 )
		{
			m_status |= HUC6270_VD;
			m_irq_changed_cb( ASSERT_LINE );
		}

		/* Should we initiate a VRAM->SATB DMA transfer.
		   The timing for this is incorrect.
		 */
		if ( m_dvssr_written || ( m_dcr & 0x10 ) )
		{
			int i;

			LOG("SATB transfer from %05x\n", m_dvssr << 1 );
			for ( i = 0; i < 4 * 64; i += 4 )
			{
				m_sat[i + 0] = m_vram[ ( m_dvssr + i + 0 ) & m_vram_mask ] & 0x03FF;
				m_sat[i + 1] = m_vram[ ( m_dvssr + i + 1 ) & m_vram_mask ] & 0x03FF;
				m_sat[i + 2] = m_vram[ ( m_dvssr + i + 2 ) & m_vram_mask ] & 0x07FF;
				m_sat[i + 3] = m_vram[ ( m_dvssr + i + 3 ) & m_vram_mask ];
			}
			m_dvssr_written = 0;

			/* Generate SATB interrupt if requested */
			if ( m_dcr & 0x01 )
			{
				m_satb_countdown = 4;
//                  m_status |= HUC6270_DS;
//                  m_irq_changed_cb( ASSERT_LINE );
			}
		}

		m_vd_triggered = 1;
	}
}


inline void huc6270_device::next_vert_state()
{
	switch ( m_vert_state )
	{
	case v_state::VSW:
		m_vert_state = v_state::VDS;
		m_vert_to_go = ( ( m_vpr >> 8 ) & 0xFF ) + 2;
		break;

	case v_state::VDS:
		m_vert_state = v_state::VDW;
		m_vert_to_go = ( m_vdw & 0x1FF ) + 1;
		m_byr_latched = m_byr;
		m_vd_triggered = 0;
		break;

	case v_state::VDW:
		m_vert_state = v_state::VCR;
		m_vert_to_go = ( m_vcr & 0xFF );
		handle_vblank();
		break;

	case v_state::VCR:
		m_vert_state = v_state::VSW;
		m_vert_to_go = ( m_vpr & 0x1F ) + 1;
		break;
	}
}


inline void huc6270_device::next_horz_state()
{
	switch ( m_horz_state )
	{
	case h_state::HDS:
		m_bxr_latched = m_bxr;
		m_horz_state = h_state::HDW;
		m_horz_to_go = ( m_hdr & 0x7F ) + 1;
		{
			static const int width_shift[4] = { 5, 6, 7, 7 };
			uint16_t v;

			v = ( m_byr_latched ) & ( ( m_mwr & 0x40 ) ? 0x1FF : 0xFF );
			m_bat_row = v & 7;
			m_bat_address_mask = ( 1 << width_shift[ ( m_mwr >> 4 ) & 0x03 ] ) - 1;
			m_bat_address = ( ( v >> 3 ) << ( width_shift[ ( m_mwr >> 4 ) & 0x03 ] ) )
				| ( ( m_bxr_latched >> 3 ) & m_bat_address_mask );
			m_bat_column = m_bxr & 7;
			fetch_bat_tile_row();
		}
		break;

	case h_state::HDW:
		m_horz_state = h_state::HDE;
		m_horz_to_go = ( ( m_hdr >> 8 ) & 0x7F ) + 1;
		break;

	case h_state::HDE:
		m_horz_state = h_state::HSW;
		m_horz_to_go = ( m_hsr & 0x1F ) + 1;
		break;

	case h_state::HSW:
		m_horz_state = h_state::HDS;
		m_horz_to_go = std::max( ( ( m_hsr >> 8 ) & 0x7F ), 2 ) + 1;

		/* If section has ended, advance to next vertical state */
		while ( m_vert_to_go == 0 )
			next_vert_state();

		/* Select sprites for the coming line */
		select_sprites();
		break;
	}
	m_horz_steps = 0;
}


u16 huc6270_device::next_pixel()
{
	uint16_t data = HUC6270_SPRITE;

	/* Check if we're on an active display line */
	if ( m_vert_state == v_state::VDW )
	{
		/* Check if we're in active display area */
		if ( m_horz_state == h_state::HDW )
		{
			uint8_t sprite_data = m_sprite_row[ m_sprite_row_index ] & 0x00FF;
			int collission = ( m_sprite_row[ m_sprite_row_index ] & 0x8000 ) ? 1 : 0;

			if ( m_cr & 0x80 )
			{
				data = HUC6270_BACKGROUND | m_bat_tile_row[ m_bat_column ];
				if ( sprite_data && ( m_cr & 0x40 ) )
				{
					if ( m_sprite_row[ m_sprite_row_index ] & 0x4000 )
					{
						data = HUC6270_SPRITE | sprite_data;
					}
					else
					{
						if ( data == HUC6270_BACKGROUND )
						{
							data = HUC6270_SPRITE | sprite_data;
						}
					}
				}
			}
			else
			{
				if ( m_cr & 0x40 )
				{
					data = HUC6270_SPRITE | sprite_data;
				}
			}

			m_sprite_row_index = m_sprite_row_index + 1;
			m_bat_column += 1;
			if ( m_bat_column >= 8 )
			{
				m_bat_address = ( m_bat_address & ~m_bat_address_mask )
					| ( ( m_bat_address + 1 ) & m_bat_address_mask );
				m_bat_column = 0;
				fetch_bat_tile_row();
			}

			if ( collission && ( m_cr & 0x01 ) )
			{
				m_status |= HUC6270_CR;
				m_irq_changed_cb( ASSERT_LINE );
			}
		}
	}

	m_horz_steps++;
	if ( m_horz_steps == 8 )
	{
		m_horz_to_go -= 1;
		m_horz_steps = 0;
		while ( m_horz_to_go == 0 )
			next_horz_state();
	}
	return data;
}


//inline u16 huc6270_device::time_until_next_event()
//{
//  return m_horz_to_go * 8 + m_horz_steps;
//}


WRITE_LINE_MEMBER( huc6270_device::vsync_changed )
{
	state &= 0x01;
	if ( m_vsync != state )
	{
		/* Check for high->low VSYNC transition */
		if ( !state )
		{
			m_vert_state = v_state::VCR;
			m_vert_to_go = 0;

			while ( m_vert_to_go == 0 )
				next_vert_state();
		}
		else
		{
			/* Check for low->high VSYNC transition */
			// VBlank IRQ happens at the beginning of HDW period after VDW ends
			handle_vblank();
		}
	}

	m_vsync = state;
}


WRITE_LINE_MEMBER( huc6270_device::hsync_changed )
{
	state &= 0x01;

	if(m_hsync != state)
	{
		/* Check for low->high HSYNC transition */
		if(state)
		{
			if ( m_satb_countdown )
			{
				m_satb_countdown--;

				if ( m_satb_countdown == 0 )
				{
					m_status |= HUC6270_DS;
					m_irq_changed_cb( ASSERT_LINE );
				}
			}

			m_horz_state = h_state::HSW;
			m_horz_to_go = 0;
			m_horz_steps = 0;
			m_byr_latched += 1;
			m_raster_count += 1;
			if ( m_vert_to_go == 1 && m_vert_state == v_state::VDS )
			{
				m_raster_count = 0x40;
			}

			m_vert_to_go -= 1;

			while ( m_horz_to_go == 0 )
				next_horz_state();

			handle_dma();
		}
		else
		{
			/* Check for high->low HSYNC transition */
			// RCR IRQ happens near the end of the HDW period
			if ( m_raster_count == m_rcr && ( m_cr & 0x04 ) )
			{
				m_status |= HUC6270_RR;
				m_irq_changed_cb( ASSERT_LINE );
			}
		}
	}

	m_hsync = state;
}

inline void huc6270_device::handle_dma()
{
	/* Should we perform VRAM-VRAM dma.
	   The timing for this is incorrect.
	 */
	if ( m_dma_enabled )
	{
		int desr_inc = ( m_dcr & 0x0008 ) ? -1 : +1;
		int sour_inc = ( m_dcr & 0x0004 ) ? -1 : +1;

		LOG("doing dma sour = %04x, desr = %04x, lenr = %04x\n", m_sour, m_desr, m_lenr );

		do {
			uint16_t data;

			// area 0x8000-0xffff cannot be r/w (open bus)
			if(m_sour <= m_vram_mask)
				data = m_vram[ m_sour ];
			else
				data = 0;

			if(m_desr <= m_vram_mask)
				m_vram[ m_desr ] = data;
			m_sour += sour_inc;
			m_desr += desr_inc;
			m_lenr -= 1;
		} while ( m_lenr != 0xFFFF );

		if ( m_dcr & 0x0002 )
		{
			m_status |= HUC6270_DV;
			m_irq_changed_cb( ASSERT_LINE );
		}
		m_dma_enabled = 0;
	}
}

u8 huc6270_device::read(offs_t offset)
{
	uint8_t data = 0x00;

	switch ( offset & 3 )
	{
		case 0x00:  /* status */
			data = m_status;
			m_status &= ~( HUC6270_VD | HUC6270_DV | HUC6270_RR | HUC6270_CR | HUC6270_OR | HUC6270_DS );
			m_irq_changed_cb( CLEAR_LINE );
			break;

		case 0x02:
			data = m_vrr & 0xFF;
			break;

		case 0x03:
			data = m_vrr >> 8;
			if ( m_register_index == VxR )
			{
				m_marr += vram_increments[ ( m_cr >> 11 ) & 3 ];

				if(m_marr <= m_vram_mask)
					m_vrr = m_vram[ m_marr ];
				else
				{
					// TODO: test with real HW
					m_vrr = 0;
					logerror("%s Open Bus VRAM read (register read) %04x\n",this->tag(),m_marr);
				}
			}
			break;
	}
	return data;
}


void huc6270_device::write(offs_t offset, u8 data)
{
	LOG("%s: huc6270 write %02x <- %02x ", machine().describe_context(), offset, data);

	switch ( offset & 3 )
	{
		case 0x00:  /* VDC register select */
			m_register_index = data & 0x1F;
			break;

		case 0x02:  /* VDC data LSB */
			switch ( m_register_index )
			{
				case MAWR:      /* memory address write register LSB */
					m_mawr = ( m_mawr & 0xFF00 ) | data;
					break;

				case MARR:      /* memory address read register LSB */
					m_marr = ( m_marr & 0xFF00 ) | data;
					if(m_marr <= m_vram_mask)
						m_vrr = m_vram[ m_marr ];
					else
					{
						// TODO: test with real HW
						m_vrr = 0;
						logerror("%s Open Bus VRAM read (memory address) %04x\n",this->tag(),m_marr);
					}
					break;

				case VxR:       /* vram write data LSB */
					m_vwr = ( m_vwr & 0xFF00 ) | data;
					break;

				case CR:        /* control register LSB */
					m_cr = ( m_cr & 0xFF00 ) | data;
					break;

				case RCR:       /* raster compare register LSB */
					m_rcr = ( m_rcr & 0x0300 ) | data;
//                  if ( m_raster_count == m_rcr && m_cr & 0x04 )
//                  {
//                      m_status |= HUC6270_RR;
//                      m_irq_changed_cb( ASSERT_LINE );
//                  }
					break;

				case BXR:       /* background x-scroll register LSB */
					m_bxr = ( m_bxr & 0x0300 ) | data;
					break;

				case BYR:       /* background y-scroll register LSB */
					m_byr = ( m_byr & 0x0100 ) | data;
					m_byr_latched = m_byr;
					break;

				case MWR:       /* memory width register LSB */
					m_mwr = ( m_mwr & 0xFF00 ) | data;
					break;

				case HSR:       /* horizontal sync register LSB */
					m_hsr = ( m_hsr & 0xFF00 ) | data;
					break;

				case HDR:       /* horizontal display register LSB */
					m_hdr = ( m_hdr & 0xFF00 ) | data;
					break;

				case VPR:       /* vertical sync register LSB */
					m_vpr = ( m_vpr & 0xFF00 ) | data;
					break;

				case VDW:       /* vertical display register LSB */
					m_vdw = ( m_vdw & 0xFF00 ) | data;
					break;

				case VCR:       /* vertical display end position register LSB */
					m_vcr = ( m_vcr & 0xFF00 ) | data;
					break;

				case DCR:       /* DMA control register LSB */
					m_dcr = ( m_dcr & 0xFF00 ) | data;
					break;

				case SOUR:      /* DMA source address register LSB */
					m_sour = ( m_sour & 0xFF00 ) | data;
					break;

				case DESR:      /* DMA destination address register LSB */
					m_desr = ( m_desr & 0xFF00 ) | data;
					break;

				case LENR:      /* DMA length register LSB */
					m_lenr = ( m_lenr & 0xFF00 ) | data;
					break;

				case DVSSR:     /* Sprite attribute table LSB */
					m_dvssr = ( m_dvssr & 0xFF00 ) | data;
					m_dvssr_written = 1;
					break;
			}
			break;

		case 0x03:  /* VDC data MSB */
			switch ( m_register_index )
			{
				case MAWR:      /* memory address write register MSB */
					m_mawr = ( m_mawr & 0x00FF ) | ( data << 8 );
					break;

				case MARR:      /* memory address read register MSB */
					m_marr = ( m_marr & 0x00FF ) | ( data << 8 );
					if(m_marr <= m_vram_mask)
						m_vrr = m_vram[ m_marr ];
					else
						m_vrr = 0;
					break;

				case VxR:       /* vram write data MSB */
					m_vwr = ( m_vwr & 0x00FF ) | ( data << 8 );
					// area 0x8000-0xffff is NOP and cannot be written to.
					if(m_mawr <= m_vram_mask)
						m_vram[ m_mawr ] = m_vwr;
					m_mawr += vram_increments[ ( m_cr >> 11 ) & 3 ];
					break;

				case CR:        /* control register MSB */
					m_cr = ( m_cr & 0x00FF ) | ( data << 8 );
					break;

				case RCR:       /* raster compare register MSB */
					m_rcr = ( m_rcr & 0x00FF ) | ( ( data & 0x03 ) << 8 );
//printf("%s: RCR set to %03x\n", machine().describe_context().c_str(), m_rcr);
//                  if ( m_raster_count == m_rcr && m_cr & 0x04 )
//                  {
//                      m_status |= HUC6270_RR;
//                      m_irq_changed_cb( ASSERT_LINE );
//                  }
					break;

				case BXR:       /* background x-scroll register MSB */
					m_bxr = ( m_bxr & 0x00FF ) | ( ( data & 0x03 ) << 8 );
					break;

				case BYR:       /* background y-scroll register MSB */
					m_byr = ( m_byr & 0x00FF ) | ( ( data & 0x01 ) << 8 );
					m_byr_latched = m_byr;
					break;

				case MWR:       /* memory width register MSB */
					m_mwr = ( m_mwr & 0x00FF ) | ( data << 8 );
					break;

				case HSR:       /* horizontal sync register MSB */
					m_hsr = ( m_hsr & 0x00FF ) | ( data << 8 );
					break;

				case HDR:       /* horizontal display register MSB */
					m_hdr = ( m_hdr & 0x00FF ) | ( data << 8 );
					break;

				case VPR:       /* vertical sync register MSB */
					m_vpr = ( m_vpr & 0x00FF ) | ( data << 8 );
					break;

				case VDW:       /* vertical display register MSB */
					m_vdw = ( m_vdw & 0x00FF ) | ( data << 8 );
					break;

				case VCR:       /* vertical display end position register MSB */
					m_vcr = ( m_vcr & 0x00FF ) | ( data << 8 );
					break;

				case DCR:       /* DMA control register MSB */
					m_dcr = ( m_dcr & 0x00FF ) | ( data << 8 );
					break;

				case SOUR:      /* DMA source address register MSB */
					m_sour = ( m_sour & 0x00FF ) | ( data << 8 );
					break;

				case DESR:      /* DMA destination address register MSB */
					m_desr = ( m_desr & 0x00FF ) | ( data << 8 );
					break;

				case LENR:      /* DMA length register MSB */
					m_lenr = ( m_lenr & 0x00FF ) | ( data << 8 );
					m_dma_enabled = 1;
//logerror("DMA is not supported yet.\n");
					break;

				case DVSSR:     /* Sprite attribute table MSB */
					m_dvssr = ( m_dvssr & 0x00FF ) | ( data << 8 );
					m_dvssr_written = 1;
					break;
			}
			break;
	}
	LOG("\n");
}


void huc6270_device::device_start()
{
	/* Resolve callbacks */
	m_irq_changed_cb.resolve_safe();

	m_vram = make_unique_clear<uint16_t[]>(m_vram_size/sizeof(uint16_t));
	m_vram_mask = (m_vram_size >> 1) - 1;

	save_pointer(NAME(m_vram), m_vram_size/sizeof(uint16_t));

	save_item(NAME(m_register_index));
	save_item(NAME(m_mawr));
	save_item(NAME(m_marr));
	save_item(NAME(m_vrr));
	save_item(NAME(m_vwr));
	save_item(NAME(m_cr));
	save_item(NAME(m_rcr));
	save_item(NAME(m_bxr));
	save_item(NAME(m_byr));
	save_item(NAME(m_mwr));
	save_item(NAME(m_hsr));
	save_item(NAME(m_hdr));
	save_item(NAME(m_vpr));
	save_item(NAME(m_vdw));
	save_item(NAME(m_vcr));
	save_item(NAME(m_dcr));
	save_item(NAME(m_sour));
	save_item(NAME(m_desr));
	save_item(NAME(m_lenr));
	save_item(NAME(m_dvssr));
	save_item(NAME(m_status));
	save_item(NAME(m_hsync));
	save_item(NAME(m_vsync));
	save_item(NAME(m_vert_state));
	save_item(NAME(m_horz_state));
	save_item(NAME(m_vd_triggered));
	save_item(NAME(m_vert_to_go));
	save_item(NAME(m_horz_to_go));
	save_item(NAME(m_horz_steps));
	save_item(NAME(m_raster_count));
	save_item(NAME(m_dvssr_written));
	save_item(NAME(m_satb_countdown));
	save_item(NAME(m_dma_enabled));
	save_item(NAME(m_byr_latched));
	save_item(NAME(m_bxr_latched));
	save_item(NAME(m_bat_address));
	save_item(NAME(m_bat_address_mask));
	save_item(NAME(m_bat_row));
	save_item(NAME(m_bat_column));
	save_item(NAME(m_bat_tile_row));
	save_item(NAME(m_sat));
	save_item(NAME(m_sprites_this_line));
	save_item(NAME(m_sprite_row_index));
	save_item(NAME(m_sprite_row));
}


void huc6270_device::device_reset()
{
	m_mawr = 0;
	m_marr = 0;
	m_vrr = 0;
	m_vwr = 0;
	m_cr = 0;
	m_rcr = 0;
	m_bxr = 0;
	m_byr = 0;
	m_mwr = 0;
	m_hsr = 0x0202;     /* Take some defaults for horizontal timing */
	m_hdr = 0x041f;
	m_vpr = 0x0f02;     /* Take some defaults for vertical timing */
	m_vdw = 0x00ef;
	m_vcr = 0x0004;
	m_dcr = 0;
	m_sour = 0;
	m_lenr = 0;
	m_dvssr = 0;
	m_status = 0;
	m_vd_triggered = 0;
	m_dvssr_written = 0;
	m_satb_countdown = 0;
	m_raster_count = 0x4000;
	m_vert_to_go = 0;
	m_vert_state = v_state::VSW;
	m_horz_steps = 0;
	m_horz_to_go = 0;
	m_horz_state = h_state::HDS;
	m_hsync = 0;
	m_vsync = 0;
	m_dma_enabled = 0;
	m_byr_latched = 0;

	memset(m_sat, 0, sizeof(m_sat));
}