summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/bus/gba/rom.cpp
blob: 643432b843395d272ec58e8445ec6aadf69d2493 (plain) (tree)
1
2
3
4
5
6
7
8
9
                       
                                                       

                                                                                                            
 



                                                                                  

 




                                                                                                             
                





                                                   












                                                                                                                                         

 


                                                                                                                                 


 
                                                                                                               
                                                                 


 

                                                                                                                                           


 
                                                                                                                         
                                                                       


 
                                                                                                                                 
                                                                           
                                   


 
                                                                                                                                 
                                                                           
                                   
                                  


 

                                                                                                                                               


 
                                                                                                                             
                                                                           


 
                                                                                                                               


                                                                            


 

                                                                                                                                                   


 
                                                                                                                                 
                                                                               


 
                                                                                                                             

                                                                             


 



                                                                                                                                             


 
                                                                                                                           
                                                                         


 
                                                                                                                                   
                                                                             


 



                                                                                                                                                 


 
                                                                                                                               
                                                                             


 
                                                                                                                                       
                                                                                 


 
                                                                                                                                 
                                                                      


 

                                                   




                                                   


                                           



                                   



                           
                              


                        





                                            

                                            

                                       







                                            














                                           

                                       
                                                                                             
                           
                                                                                                                   

 















                                              

                                            
                                                                                             
                            
                                                                                                                    

 
















                                                              
                                       




                                                              
                                       


                                                              

                                            
                                       











                                            




                                                    



                                                                       
 






                                                          
                                                                    
 







                                                        
                                                                                  



                                                                    
                                                











                                                                    
                                                                                
 

























                                                                           




                                                    
                                                                        
 
                                                        
                                       
                                                 


                                  
                                                                                    
 
                                                        



                                               

                                                                       
                                                                          



                                                
                                        















                                                                                                                    
                                                              






                                                        
                                                                          



                                                
                                        








                                                  
 





                                         



                                                    



                                                                     
 
 
                                                                         
 
                        
 
                               

                            
                                                
                              
                                                           
                                
                                                            
                                  
                                                            
 


                  
                                                                                     

                               
 


                          
                                                                

                              
                                                                             

                              
                                                                              

                                
                                                                              


                                                                                          


         



                                                                       
 
 
                                                                           
 
                        
 

                               
                            
                                                
                              
                                                           
                                
                                                            
                                  
                                                            
 


                  
                                                                                       





                               
                                                                

                              
                                                                             

                              
                                                                              

                                
                                                                              


                                                                                          


         

                                          
                                                               



                                             
                                                                           




                                      
                                                                 



                                             
                                                                             



                                      


                                                   

                                                    
                                                                          







                                                                   
                                                                                      










                                                                   
                                                                            







                                                                   
                                                                                        













                                                                   

                                                



                                                    


                                                     
                                             
                                                
                                                     
 














                                                                                                                    
                                                                            
























                                                                     
                                                                     













































                                                                    
                                                            




                                                                              
                                                                        





                                      
 





                                                    
 


                                      
 






























                                                         
                                                                        
 
                                                                               


                           

                                                                          
                                                                                                                



                                                                              

                                                                        

                              
                                                                        
                                              



                                                                                    



                                                   
                                                                           










                                                                            
 












                                                              
 








                                                                     
                                                 







                                                      
 






























                                                                                                                                              
                                                                                                 








                                                         
                                                          
 
                                             







                                                                                  

                                       
                                                    












                                                                                                                        
                                                                                                                        





























































                                                                                                                
 
                                               
                                    

                                                    
  
 
                                                                                                               

                                                          



                                
 





                                                                        

 
                                  
 
                     
 


                              
                                                      
 

                                   
 



















                                                                                                                          
 


                                                          
 

                                  
 



                                                   
 

                                   


                 
                                            
 





                                          
 








                                                          
 

















                                                                              
 







                                                     
 




                                                 
 

                                        
                                                                                                                                 

                                                                                             
 




                                                            
 


                                                         
 




                                           
// license:BSD-3-Clause
// copyright-holders:R. Belmont,Ryan Holtz,Fabio Priuli
/***********************************************************************************************************


 Game Boy Advance cart emulation


 We support carts with several kind of Save RAM (actual SRAM, Flash RAM or EEPROM)



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


#include "emu.h"
#include "rom.h"


//-------------------------------------------------
//  gba_rom_device - constructor
//-------------------------------------------------

DEFINE_DEVICE_TYPE(GBA_ROM_STD,         gba_rom_device,             "gba_rom",             "GBA Carts")
DEFINE_DEVICE_TYPE(GBA_ROM_SRAM,        gba_rom_sram_device,        "gba_rom_sram",        "GBA Carts + SRAM")
DEFINE_DEVICE_TYPE(GBA_ROM_DRILLDOZ,    gba_rom_drilldoz_device,    "gba_rom_drilldoz",    "GBA Carts + SRAM + Rumble")
DEFINE_DEVICE_TYPE(GBA_ROM_WARIOTWS,    gba_rom_wariotws_device,    "gba_rom_wariotws",    "GBA Carts + SRAM + Rumble + Gyroscope")
DEFINE_DEVICE_TYPE(GBA_ROM_EEPROM,      gba_rom_eeprom_device,      "gba_rom_eeprom",      "GBA Carts + EEPROM")
DEFINE_DEVICE_TYPE(GBA_ROM_YOSHIUG,     gba_rom_yoshiug_device,     "gba_rom_yoshiug",     "GBA Carts + EEPROM + Tilt Sensor")
DEFINE_DEVICE_TYPE(GBA_ROM_EEPROM64,    gba_rom_eeprom64_device,    "gba_rom_eeprom64",    "GBA Carts + EEPROM 64K")
DEFINE_DEVICE_TYPE(GBA_ROM_BOKTAI,      gba_rom_boktai_device,      "gba_rom_boktai",      "GBA Carts + EEPROM 64K + RTC + Light Sensor")
DEFINE_DEVICE_TYPE(GBA_ROM_FLASH,       gba_rom_flash_device,       "gba_rom_flash",       "GBA Carts + Panasonic Flash")
DEFINE_DEVICE_TYPE(GBA_ROM_FLASH_RTC,   gba_rom_flash_rtc_device,   "gba_rom_flash_rtc",   "GBA Carts + Panasonic Flash + RTC")
DEFINE_DEVICE_TYPE(GBA_ROM_FLASH1M,     gba_rom_flash1m_device,     "gba_rom_flash1m",     "GBA Carts + Sanyo Flash")
DEFINE_DEVICE_TYPE(GBA_ROM_FLASH1M_RTC, gba_rom_flash1m_rtc_device, "gba_rom_flash1m_rtc", "GBA Carts + Sanyo Flash + RTC")
DEFINE_DEVICE_TYPE(GBA_ROM_3DMATRIX,    gba_rom_3dmatrix_device,    "gba_rom_3dmatrix",    "3D Matrix Memory Mapper")


gba_rom_device::gba_rom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, type, tag, owner, clock)
	, device_gba_cart_interface(mconfig, *this)
{
}

gba_rom_device::gba_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_device(mconfig, GBA_ROM_STD, tag, owner, clock)
{
}

gba_rom_sram_device::gba_rom_sram_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_device(mconfig, type, tag, owner, clock)
{
}

gba_rom_sram_device::gba_rom_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_sram_device(mconfig, GBA_ROM_SRAM, tag, owner, clock)
{
}

gba_rom_drilldoz_device::gba_rom_drilldoz_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_sram_device(mconfig, GBA_ROM_DRILLDOZ, tag, owner, clock)
	, m_rumble(*this, "Rumble")
{
}

gba_rom_wariotws_device::gba_rom_wariotws_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_sram_device(mconfig, GBA_ROM_WARIOTWS, tag, owner, clock)
	, m_rumble(*this, "Rumble")
	, m_gyro_z(*this, "GYROZ")
{
}

gba_rom_eeprom_device::gba_rom_eeprom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_device(mconfig, type, tag, owner, clock)
{
}

gba_rom_eeprom_device::gba_rom_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_eeprom_device(mconfig, GBA_ROM_EEPROM, tag, owner, clock)
{
}

gba_rom_yoshiug_device::gba_rom_yoshiug_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_eeprom_device(mconfig, GBA_ROM_YOSHIUG, tag, owner, clock)
	, m_tilt_x(*this, "TILTX")
	, m_tilt_y(*this, "TILTY")
{
}

gba_rom_eeprom64_device::gba_rom_eeprom64_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_device(mconfig, type, tag, owner, clock)
{
}

gba_rom_eeprom64_device::gba_rom_eeprom64_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_eeprom64_device(mconfig, GBA_ROM_EEPROM64, tag, owner, clock)
{
}

gba_rom_boktai_device::gba_rom_boktai_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_eeprom64_device(mconfig, GBA_ROM_BOKTAI, tag, owner, clock)
	, m_sensor(*this, "LIGHTSENSE")
{
}

gba_rom_flash_device::gba_rom_flash_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_device(mconfig, type, tag, owner, clock)
	, m_flash_mask(0)
	, m_flash(*this, "flash")
{
}

gba_rom_flash_device::gba_rom_flash_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_flash_device(mconfig, GBA_ROM_FLASH, tag, owner, clock)
{
}

gba_rom_flash_rtc_device::gba_rom_flash_rtc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_flash_device(mconfig, GBA_ROM_FLASH_RTC, tag, owner, clock)
{
}

gba_rom_flash1m_device::gba_rom_flash1m_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_device(mconfig, type, tag, owner, clock)
	, m_flash_mask(0)
	, m_flash(*this, "flash")
{
}

gba_rom_flash1m_device::gba_rom_flash1m_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_flash1m_device(mconfig, GBA_ROM_FLASH1M, tag, owner, clock)
{
}

gba_rom_flash1m_rtc_device::gba_rom_flash1m_rtc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_flash1m_device(mconfig, GBA_ROM_FLASH1M_RTC, tag, owner, clock)
{
}

gba_rom_3dmatrix_device::gba_rom_3dmatrix_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gba_rom_device(mconfig, GBA_ROM_3DMATRIX, tag, owner, clock)
{
}


//-------------------------------------------------
//  mapper specific start/reset
//-------------------------------------------------

void gba_rom_device::device_start()
{
	save_item(NAME(m_gpio_regs));
	save_item(NAME(m_gpio_write_only));
	save_item(NAME(m_gpio_dirs));
}

void gba_rom_device::device_reset()
{
	m_gpio_regs[0] = 0;
	m_gpio_regs[1] = 0;
	m_gpio_regs[2] = 0;
	m_gpio_regs[3] = 0;
	m_gpio_write_only = 1;
	m_gpio_dirs = 0;
}

void gba_rom_drilldoz_device::device_start()
{
	gba_rom_device::device_start();
	m_rumble.resolve();
}

void gba_rom_wariotws_device::device_start()
{
	gba_rom_device::device_start();
	m_rumble.resolve();
	save_item(NAME(m_last_val));
	save_item(NAME(m_counter));
}

void gba_rom_wariotws_device::device_reset()
{
	m_last_val = 0;
	m_counter = 0;
}

void gba_rom_flash_device::device_reset()
{
	m_flash_mask = 0xffff/4;
}

void gba_rom_flash1m_device::device_reset()
{
	m_flash_mask = 0x1ffff/4;
}


void gba_rom_eeprom_device::device_start()
{
	gba_rom_device::device_start();

	// for the moment we use a custom eeprom implementation, so we alloc/save it as nvram
	nvram_alloc(0x200);
	m_eeprom = std::make_unique<gba_eeprom_device>(machine(), (uint8_t*)get_nvram_base(), get_nvram_size(), 6);
}

void gba_rom_yoshiug_device::device_start()
{
	gba_rom_eeprom_device::device_start();
	save_item(NAME(m_tilt_ready));
	save_item(NAME(m_xpos));
	save_item(NAME(m_ypos));
}

void gba_rom_yoshiug_device::device_reset()
{
	m_tilt_ready = 0;
	m_xpos = 0;
	m_ypos = 0;
}


void gba_rom_eeprom64_device::device_start()
{
	// for the moment we use a custom eeprom implementation, so we alloc/save it as nvram
	nvram_alloc(0x2000);
	m_eeprom = std::make_unique<gba_eeprom_device>(machine(), (uint8_t*)get_nvram_base(), get_nvram_size(), 14);
}

void gba_rom_boktai_device::device_start()
{
	gba_rom_eeprom64_device::device_start();
	m_rtc = std::make_unique<gba_s3511_device>(machine());

	save_item(NAME(m_last_val));
	save_item(NAME(m_counter));
}

void gba_rom_boktai_device::device_reset()
{
	m_last_val = 0;
	m_counter = 0;
}

void gba_rom_flash_rtc_device::device_start()
{
	gba_rom_device::device_start();
	m_rtc = std::make_unique<gba_s3511_device>(machine());
}

void gba_rom_flash1m_rtc_device::device_start()
{
	gba_rom_device::device_start();
	m_rtc = std::make_unique<gba_s3511_device>(machine());
}

void gba_rom_3dmatrix_device::device_start()
{
	gba_rom_device::device_start();
	save_item(NAME(m_src));
	save_item(NAME(m_dst));
	save_item(NAME(m_nblock));
}

void gba_rom_3dmatrix_device::device_reset()
{
	m_src = 0;
	m_dst = 0;
	m_nblock = 0;
}


/*-------------------------------------------------
 mapper specific handlers
 -------------------------------------------------*/

/*-------------------------------------------------
 This is a preliminary implementation of the
 General Purpose I/O Port embedded in the GBA PCBs
 as described at : http://problemkaputt.de/gbatek.htm#gbacartioportgpio

 Functions read_gpio/write_gpio only give the
 I/O interface while the actual on-cart devices
 are read and written through gpio_dev_read/gpio_dev_write
 which are virtual methods defined in the specific
 cart types.
 -------------------------------------------------*/

uint32_t gba_rom_device::read_gpio(offs_t offset, uint32_t mem_mask)
{
	if (!m_gpio_write_only)
	{
		switch (offset)
		{
			case 0:
			default:
				if (ACCESSING_BITS_0_15)
				{
					uint16_t ret = gpio_dev_read(m_gpio_dirs);
					return ret;
				}
				if (ACCESSING_BITS_16_31)
					return m_gpio_regs[1] << 16;
				[[fallthrough]];
			case 1:
				if (ACCESSING_BITS_0_15)
					return m_gpio_regs[2];
				if (ACCESSING_BITS_16_31)
					return m_gpio_regs[3] << 16;
		}
		return 0;
	}
	else
		return m_rom[offset + 0xc4/4];
}

void gba_rom_device::write_gpio(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	switch (offset)
	{
		case 0:
		default:
			if (ACCESSING_BITS_0_15)
			{
				gpio_dev_write(data & 0xffff, m_gpio_dirs);
			}
			if (ACCESSING_BITS_16_31)
			{
				m_gpio_dirs = (data >> 16) & 0x0f;
				m_gpio_regs[1] = (data >> 16) & 0xffff;
			}
			break;
		case 1:
			if (ACCESSING_BITS_0_15)
			{
				m_gpio_write_only = BIT(data, 0) ? 0 : 1;
				m_gpio_regs[2] = data & 0xffff;
			}
			if (ACCESSING_BITS_16_31)
				m_gpio_regs[3] = (data >> 16) & 0xffff;
			break;
	}
}


/*-------------------------------------------------
 Carts with SRAM
 -------------------------------------------------*/

uint32_t gba_rom_sram_device::read_ram(offs_t offset, uint32_t mem_mask)
{
	if (!m_nvram.empty() && offset < m_nvram.size())
		return m_nvram[offset];
	else    // this cannot actually happen...
		return 0xffffffff;
}

void gba_rom_sram_device::write_ram(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	if (!m_nvram.empty() && offset < m_nvram.size())
		COMBINE_DATA(&m_nvram[offset]);
}


// SRAM cart variant with additional Rumble motor (used by Drill Dozer)

void gba_rom_drilldoz_device::gpio_dev_write(uint16_t data, int gpio_dirs)
{
	if ((gpio_dirs & 0x08))
	{
		// send impulse to Rumble sensor
		m_rumble = BIT(data, 3);
	}
}


// SRAM cart variant with additional Rumble motor + Gyroscope (used by Warioware Twist)

static INPUT_PORTS_START( wariotws_gyroscope )
	PORT_START("GYROZ")
	PORT_BIT( 0xfff, 0x6c0, IPT_AD_STICK_Z ) PORT_MINMAX(0x354,0x9e3) PORT_SENSITIVITY(0x10) PORT_KEYDELTA(0x50)
INPUT_PORTS_END

ioport_constructor gba_rom_wariotws_device::device_input_ports() const
{
	return INPUT_PORTS_NAME( wariotws_gyroscope );
}

uint16_t gba_rom_wariotws_device::gpio_dev_read(int gpio_dirs)
{
	int gyro = 0;
	if (gpio_dirs == 0x0b)
		gyro = BIT(m_gyro_z->read(), m_counter);
	return (gyro << 2);
}

void gba_rom_wariotws_device::gpio_dev_write(uint16_t data, int gpio_dirs)
{
	if ((gpio_dirs & 0x08))
	{
		// send impulse to Rumble sensor
		m_rumble = BIT(data, 3);
	}

	if (gpio_dirs == 0x0b)
	{
		if ((data & 2) && (m_counter > 0))
			m_counter--;

		if (data & 1)
			m_counter = 15;

		m_last_val = data & 0x0b;
	}
}



/*-------------------------------------------------
 Carts with Flash RAM
 -------------------------------------------------*/

void gba_rom_flash_device::device_add_mconfig(machine_config &config)
{
	PANASONIC_MN63F805MNP(config, "flash");
}


uint32_t gba_rom_flash_device::read_ram(offs_t offset, uint32_t mem_mask)
{
	uint32_t rv = 0;

	offset &= m_flash_mask;

	if (mem_mask & 0xff)
		rv |= m_flash->read(offset * 4);
	if (mem_mask & 0xff00)
		rv |= m_flash->read((offset * 4) + 1) << 8;
	if (mem_mask & 0xff0000)
		rv |= m_flash->read((offset * 4) + 2) << 16;
	if (mem_mask & 0xff000000)
		rv |= m_flash->read((offset * 4) + 3) << 24;

	return rv;
}

void gba_rom_flash_device::write_ram(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	offset &= m_flash_mask;

	switch (mem_mask)
	{
		case 0xff:
			m_flash->write(offset * 4, data & 0xff);
			break;
		case 0xff00:
			m_flash->write((offset * 4) + 1, (data >> 8) & 0xff);
			break;
		case 0xff0000:
			m_flash->write((offset * 4) + 2, (data >> 16) & 0xff);
			break;
		case 0xff000000:
			m_flash->write((offset * 4) + 3, (data >> 24) & 0xff);
			break;
		default:
			fatalerror("Unknown mem_mask for GBA flash write %x\n", mem_mask);
	}
}

void gba_rom_flash1m_device::device_add_mconfig(machine_config &config)
{
	SANYO_LE26FV10N1TS(config, "flash");
}


uint32_t gba_rom_flash1m_device::read_ram(offs_t offset, uint32_t mem_mask)
{
	uint32_t rv = 0;

	offset &= m_flash_mask;

	if (mem_mask & 0xff)
		rv |= m_flash->read(offset * 4);
	if (mem_mask & 0xff00)
		rv |= m_flash->read((offset * 4) + 1) << 8;
	if (mem_mask & 0xff0000)
		rv |= m_flash->read((offset * 4) + 2) << 16;
	if (mem_mask & 0xff000000)
		rv |= m_flash->read((offset * 4) + 3) << 24;

	return rv;
}

void gba_rom_flash1m_device::write_ram(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	offset &= m_flash_mask;

	switch (mem_mask)
	{
		case 0xff:
			m_flash->write(offset * 4, data & 0xff);
			break;
		case 0xff00:
			m_flash->write((offset * 4) + 1, (data >> 8) & 0xff);
			break;
		case 0xff0000:
			m_flash->write((offset * 4) + 2, (data >> 16) & 0xff);
			break;
		case 0xff000000:
			m_flash->write((offset * 4) + 3, (data >> 24) & 0xff);
			break;
		default:
			fatalerror("Unknown mem_mask for GBA flash write %x\n", mem_mask);
	}
}

// cart variants with additional S3511 RTC

uint16_t gba_rom_flash_rtc_device::gpio_dev_read(int gpio_dirs)
{
	return 5 | (m_rtc->read_line() << 1);
}

void gba_rom_flash_rtc_device::gpio_dev_write(uint16_t data, int gpio_dirs)
{
	m_rtc->write(data, gpio_dirs);
}


uint16_t gba_rom_flash1m_rtc_device::gpio_dev_read(int gpio_dirs)
{
	return 5 | (m_rtc->read_line() << 1);
}

void gba_rom_flash1m_rtc_device::gpio_dev_write(uint16_t data, int gpio_dirs)
{
	m_rtc->write(data, gpio_dirs);
}


/*-------------------------------------------------
 Carts with EEPROM
 -------------------------------------------------*/

uint32_t gba_rom_eeprom_device::read_ram(offs_t offset, uint32_t mem_mask)
{
	// Larger games have smaller access to EERPOM content
	if (m_rom_size > (16 * 1024 * 1024) && offset < 0xffff00/4)
		return 0xffffffff;

	return m_eeprom->read();
}

void gba_rom_eeprom_device::write_ram(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	// Larger games have smaller access to EEPROM content
	if (m_rom_size > (16 * 1024 * 1024) && offset < 0xffff00/4)
		return;

	if (~mem_mask == 0x0000ffff)
		data >>= 16;

	m_eeprom->write(data);
}

uint32_t gba_rom_eeprom64_device::read_ram(offs_t offset, uint32_t mem_mask)
{
	// Larger games have smaller access to EERPOM content
	if (m_rom_size > (16 * 1024 * 1024) && offset < 0xffff00/4)
		return 0xffffffff;

	return m_eeprom->read();
}

void gba_rom_eeprom64_device::write_ram(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	// Larger games have smaller access to EEPROM content
	if (m_rom_size > (16 * 1024 * 1024) && offset < 0xffff00/4)
		return;

	if (~mem_mask == 0x0000ffff)
		data >>= 16;

	m_eeprom->write(data);
}


/*-------------------------------------------------
 Carts with EEPROM + Tilt Sensor

 Note about the calibration: this can seem a bit
 tricky at first, because the emulated screen
 does not turn as the GBA would...
 In order to properly calibrate the sensor, just
 keep pressed right for a few seconds when requested
 to calibrate right inclination (first calibration
 screen in Yoshi Universal Gravitation) so to get the
 full right range; then keep pressed for left for a
 few seconds when requested to calibrate left
 inclination (second calibration screen in Yoshi
 Universal Gravitation) so to get the full left range

 -------------------------------------------------*/

static INPUT_PORTS_START( yoshiug_tilt )
	PORT_START("TILTX")
	PORT_BIT( 0xfff, 0x3a0, IPT_AD_STICK_X ) PORT_MINMAX(0x2af,0x477) PORT_SENSITIVITY(0x30) PORT_KEYDELTA(0x50)
	PORT_START("TILTY")
	PORT_BIT( 0xfff, 0x3a0, IPT_AD_STICK_Y ) PORT_MINMAX(0x2c3,0x480) PORT_SENSITIVITY(0x30) PORT_KEYDELTA(0x50)
INPUT_PORTS_END

ioport_constructor gba_rom_yoshiug_device::device_input_ports() const
{
	return INPUT_PORTS_NAME( yoshiug_tilt );
}


uint32_t gba_rom_yoshiug_device::read_tilt(offs_t offset, uint32_t mem_mask)
{
	switch (offset)
	{
		case 0x200/4:
			if (ACCESSING_BITS_0_15)
				return (m_xpos & 0xff);
			break;
		case 0x300/4:
			if (ACCESSING_BITS_0_15)
				return ((m_xpos >> 8) & 0x0f) | 0x80;
			break;
		case 0x400/4:
			if (ACCESSING_BITS_0_15)
				return (m_ypos & 0xff);
			break;
		case 0x500/4:
			if (ACCESSING_BITS_0_15)
				return ((m_ypos >> 8) & 0x0f);
			break;
		default:
			break;
	}
	return 0xffffffff;
}

void gba_rom_yoshiug_device::write_tilt(offs_t offset, uint32_t data)
{
	switch (offset)
	{
		case 0x000/4:
			if (data == 0x55) m_tilt_ready = 1;
			break;
		case 0x100/4:
			if (data == 0xaa)
			{
				m_xpos = m_tilt_x->read();
				m_ypos = m_tilt_y->read();
				m_tilt_ready = 0;
			}
			break;
		default:
			break;
	}
}


/*-------------------------------------------------
 Carts with EEPROM + S3511 RTC + Light Sensor
 -------------------------------------------------*/

static INPUT_PORTS_START( boktai_sensor )
	PORT_START("LIGHTSENSE")
	PORT_CONFNAME( 0xff, 0xe8, "Light Sensor" )
	PORT_CONFSETTING( 0xe8, "Complete Darkness" )
	PORT_CONFSETTING( 0xe4, "10%" )
	PORT_CONFSETTING( 0xdc, "20%" )
	PORT_CONFSETTING( 0xd4, "30%" )
	PORT_CONFSETTING( 0xc8, "40%" )
	PORT_CONFSETTING( 0xb8, "50%" )
	PORT_CONFSETTING( 0xa8, "60%" )
	PORT_CONFSETTING( 0x98, "70%" )
	PORT_CONFSETTING( 0x88, "80%" )
	PORT_CONFSETTING( 0x68, "90%" )
	PORT_CONFSETTING( 0x48, "Very Bright" )
INPUT_PORTS_END


ioport_constructor gba_rom_boktai_device::device_input_ports() const
{
	return INPUT_PORTS_NAME( boktai_sensor );
}

uint16_t gba_rom_boktai_device::gpio_dev_read(int gpio_dirs)
{
	int light = (gpio_dirs == 7 && m_counter >= m_sensor->read()) ? 1 : 0;
	return 5 | (m_rtc->read_line() << 1) | (light << 3);
}

void gba_rom_boktai_device::gpio_dev_write(uint16_t data, int gpio_dirs)
{
	m_rtc->write(data, gpio_dirs);
	if (gpio_dirs == 7)
	{
		if (data & 2)
			m_counter = 0;

		if ((data & 1) && !(m_last_val & 1))
		{
			m_counter++;
			if (m_counter == 0x100)
				m_counter = 0;
		}

		m_last_val = data & 7;
	}
}




/*-------------------------------------------------
 Carts with 3D Matrix Memory controller

 Used by Video carts with 64MB ROM chips
 Emulation based on the reverse engineering efforts
 by endrift

 The Memory controller basically behaves like a DMA
 chip by writing first source and destination address,
 then the number of 512K blocks to copy and finally
 by issuing the transfer command.
 Disney Collection 2 carts uses command 0x01 to start
 the transfer, other carts might use 0x11 but currently
 they die before getting to the mapper communication
 (CPU emulation issue? cart mapping issue? still unknown)

 To investigate:
 - why the other carts fail
 - which addresses might be used by the mapper
   (Disney Collection 2 uses 0x08800180-0x0880018f
   but it might well be possible to issue commands
   in an extended range...)
 - which bus addresses can be used by the mapper
   (currently we restrict the mapping in the range
   0x08000000-0x09ffffff but maybe also the rest of
   the cart "range" is accessible...)
 -------------------------------------------------*/

void gba_rom_3dmatrix_device::write_mapper(offs_t offset, uint32_t data)
{
	//printf("mapper write 0x%.8X - 0x%X\n", offset, data); fflush(stdout);
	switch (offset & 3)
	{
		case 0:
			//printf("command: %08x\n", data); fflush(stdout);
			if (data & 0x01)    // transfer data
				memcpy((uint8_t *)m_romhlp + m_dst, (uint8_t *)m_rom + m_src, m_nblock * 0x200);
			else
				printf("Unknown mapper command 0x%X\n", data);
			break;
		case 1:
			//printf("m_src: %08x\n", data); fflush(stdout);
			m_src = data & 0x3ffffff;
			break;
		case 2:
			//printf("m_dst: %08x\n", data); fflush(stdout);
			if (data >= 0xa000000)
			{
				printf("Unknown transfer destination 0x%X\n", data);
				fflush(stdout);
			}
			m_dst = (data & 0x1ffffff);
			break;
		case 3:
		default:
			//printf("m_nblock: %08x\n", data); fflush(stdout);
			m_nblock = data;
			break;
	}
}



// Additional devices, to be moved to separate source files at a later stage

/*-------------------------------------------------
 Seiko S-3511 RTC implementation

 TODO: transform this into a separate device, using
 also dirtc.cpp!
 -------------------------------------------------*/

gba_s3511_device::gba_s3511_device(running_machine &machine) :
			m_phase(S3511_RTC_IDLE),
			m_machine(machine)
{
	m_last_val = 0;
	m_bits = 0;
	m_command = 0;
	m_data_len = 1;
	m_data[0] = 0;

	m_machine.save().save_item(m_phase, "GBA_RTC/m_phase");
	m_machine.save().save_item(m_data, "GBA_RTC/m_data");
	m_machine.save().save_item(m_last_val, "GBA_RTC/m_last_val");
	m_machine.save().save_item(m_bits, "GBA_RTC/m_bits");
	m_machine.save().save_item(m_command, "GBA_RTC/m_command");
	m_machine.save().save_item(m_data_len, "GBA_RTC/m_data_len");
}


uint8_t gba_s3511_device::convert_to_bcd(int val)
{
	return (((val % 100) / 10) << 4) | (val % 10);
}

void gba_s3511_device::update_time(int len)
{
	system_time curtime;
	m_machine.current_datetime(curtime);

	if (len == 7)
	{
		m_data[0] = convert_to_bcd(curtime.local_time.year);
		m_data[1] = convert_to_bcd(curtime.local_time.month + 1);
		m_data[2] = convert_to_bcd(curtime.local_time.mday);
		m_data[3] = convert_to_bcd(curtime.local_time.weekday);
		m_data[4] = convert_to_bcd(curtime.local_time.hour);
		m_data[5] = convert_to_bcd(curtime.local_time.minute);
		m_data[6] = convert_to_bcd(curtime.local_time.second);
	}
	else if (len == 3)
	{
		m_data[0] = convert_to_bcd(curtime.local_time.hour);
		m_data[1] = convert_to_bcd(curtime.local_time.minute);
		m_data[2] = convert_to_bcd(curtime.local_time.second);
	}
}


int gba_s3511_device::read_line()
{
	int pin = 0;
	switch (m_phase)
	{
		case S3511_RTC_DATAOUT:
			//printf("mmm %d - %X - %d - %d\n", m_bits, m_data[m_bits >> 3], m_bits >> 3, BIT(m_data[m_bits >> 3], (m_bits & 7)));
			pin = BIT(m_data[m_bits >> 3], (m_bits & 7));
			m_bits++;
			if (m_bits == 8 * m_data_len)
			{
				//for (int i = 0; i < m_data_len; i++)
				//  printf("RTC DATA OUT COMPLETE %X (reg %d) \n", m_data[i], i);
				m_bits = 0;
				m_phase = S3511_RTC_IDLE;
			}
			break;
	}
	return pin;
}


void gba_s3511_device::write(uint16_t data, int gpio_dirs)
{
//  printf("gpio_dev_write data %X\n", data);
	if (m_phase == S3511_RTC_IDLE && (m_last_val & 5) == 1 && (data & 5) == 5)
	{
		m_phase = S3511_RTC_COMMAND;
		m_bits = 0;
		m_command = 0;
	}
	else
	{
//      if (m_phase == 3)
//          printf("RTC command OK\n");
		if (!(m_last_val & 1) && (data & 1))
		{
			// bit transfer
			m_last_val = data & 0xff;
			switch (m_phase)
			{
				case S3511_RTC_DATAIN:
					if (!BIT(gpio_dirs, 1))
					{
						m_data[m_bits >> 3] = (m_data[m_bits >> 3] >> 1) | ((data << 6) & 0x80);
						m_bits++;
						if (m_bits == 8 * m_data_len)
						{
							//for (int i = 0; i < m_data_len; i++)
							//  printf("RTC DATA IN COMPLETE %X (reg %d) \n", m_data[i], i);
							m_bits = 0;
							m_phase = S3511_RTC_IDLE;
						}
					}
					break;
				case S3511_RTC_DATAOUT:
					break;
				case S3511_RTC_COMMAND:
					m_command |= (BIT(data, 1) << (7 - m_bits));
					m_bits++;
					if (m_bits == 8)
					{
						m_bits = 0;
						//printf("RTC command %X ENTERED!!!\n", m_command);
						switch (m_command)
						{
							case 0x60:
								// reset?
								m_phase = S3511_RTC_IDLE;
								m_bits = 0;
								break;
							case 0x62:
								m_phase = S3511_RTC_DATAIN;
								m_data_len = 1;
								break;
							case 0x63:
								m_data_len = 1;
								m_data[0] = 0x40;
								m_phase = S3511_RTC_DATAOUT;
								break;
							case 0x64:
								break;
							case 0x65:
								m_data_len = 7;
								update_time(m_data_len);
								m_phase = S3511_RTC_DATAOUT;
								break;
							case 0x67:
								m_data_len = 3;
								update_time(m_data_len);
								m_phase = S3511_RTC_DATAOUT;
								break;
							default:
								printf("Unknown RTC command %02X\n", m_command);
								m_phase = S3511_RTC_IDLE;
								break;
						}
					}
					break;
				case S3511_RTC_IDLE:
				default:
					break;
			}
		}
		else
			m_last_val = data & 0xff;
	}
}


/*-------------------------------------------------
 GBA EEPROM Device

 TODO: can this sketchy EEPROM device be merged
       with the core implementation?
 -------------------------------------------------*/

//

gba_eeprom_device::gba_eeprom_device(running_machine &machine, uint8_t *eeprom, uint32_t size, int addr_bits) :
					m_state(EEP_IDLE),
					m_machine(machine)
{
	m_data = eeprom;
	m_data_size = size;
	m_addr_bits = addr_bits;

	m_machine.save().save_item(m_state, "GBA_EEPROM/m_state");
	m_machine.save().save_item(m_command, "GBA_EEPROM/m_command");
	m_machine.save().save_item(m_count, "GBA_EEPROM/m_count");
	m_machine.save().save_item(m_addr, "GBA_EEPROM/m_addr");
	m_machine.save().save_item(m_bits, "GBA_EEPROM/m_bits");
	m_machine.save().save_item(m_eep_data, "GBA_EEPROM/m_eep_data");
}

uint32_t gba_eeprom_device::read()
{
	uint32_t out;

	switch (m_state)
	{
		case EEP_IDLE:
			return 0x00010001;  // "ready"

		case EEP_READFIRST:
			m_count--;

			if (!m_count)
			{
				m_count = 64;
				m_bits = 0;
				m_eep_data = 0;
				m_state = EEP_READ;
			}
			break;
		case EEP_READ:
			if ((m_bits == 0) && (m_count))
			{
				if (m_addr >= m_data_size)
				{
					fatalerror("eeprom: invalid address (%x)\n", m_addr);
				}
				m_eep_data = m_data[m_addr];
				//printf("EEPROM read @ %x = %x (%x)\n", m_addr, m_eep_data, (m_eep_data & 0x80) ? 1 : 0);
				m_addr++;
				m_bits = 8;
			}

			out = (m_eep_data & 0x80) ? 1 : 0;
			out |= (out<<16);
			m_eep_data <<= 1;

			m_bits--;
			m_count--;

			if (!m_count)
			{
				m_state = EEP_IDLE;
			}

			return out;
	}
	return 0;
}

void gba_eeprom_device::write(uint32_t data)
{
	switch (m_state)
	{
		case EEP_IDLE:
			if (data == 1)
				m_state++;
			break;

		case EEP_COMMAND:
			if (data == 1)
				m_command = EEP_READFIRST;
			else
				m_command = EEP_WRITE;
			m_state = EEP_ADDR;
			m_count = m_addr_bits;
			m_addr = 0;
			break;

		case EEP_ADDR:
			m_addr <<= 1;
			m_addr |= (data & 1);
			m_count--;
			if (!m_count)
			{
				m_addr *= 8; // each address points to 8 bytes
				if (m_command == EEP_READFIRST)
					m_state = EEP_AFTERADDR;
				else
				{
					m_count = 64;
					m_bits = 8;
					m_state = EEP_WRITE;
					m_eep_data = 0;
				}
			}
			break;

		case EEP_AFTERADDR:
			m_state = m_command;
			m_count = 64;
			m_bits = 0;
			m_eep_data = 0;
			if (m_state == EEP_READFIRST)
				m_count = 4;
			break;

		case EEP_WRITE:
			m_eep_data <<= 1;
			m_eep_data |= (data & 1);
			m_bits--;
			m_count--;

			if (m_bits == 0)
			{
				osd_printf_verbose("%s: EEPROM: %02x to %x\n", machine().describe_context(), m_eep_data, m_addr);
				if (m_addr >= m_data_size)
					fatalerror("eeprom: invalid address (%x)\n", m_addr);

				m_data[m_addr] = m_eep_data;
				m_addr++;
				m_eep_data = 0;
				m_bits = 8;
			}

			if (!m_count)
				m_state = EEP_AFTERWRITE;
			break;

		case EEP_AFTERWRITE:
			m_state = EEP_IDLE;
			break;
	}
}