summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/drivers/gp32.cpp
blob: 93bc56b41ac33dcb6a6e88462ca0ff21cf84d318 (plain) (tree)
1
2
3
4
5
6
                       
                                     

                                                                           
                            
                             









                              

                        

                                                                          






                                                                        
                                                                            


                                                             


                                                                            
                          
 

                              
                           
 
                     

                    





                               
 
                           
 
                     





                          


                                                     


                 




                            
 
                                                               
 
                           



                                     
                                           

 
                                         
 




                                                                                                         
                                                                                                                                                                                                  

 
                                       
 





                                                                     

 
                                            
 
                               


                               
                                                                                                   

                                      


                                                                               
                 

                                                                                 

                 
                                     
         
                                            









                                                                                                   
                                            









                                                                                                   
                                         
 
                                        
                                                                                   


                               
                                                       

                                        
                                                                                
                                         

                                                                                     
                         


                                                                                                            




                         
                                         
 
                                        
                                                                                   


                               
                                                       

                                        
                                                                                
                                         

                                                                                     
                         


                                                                                                            




                         
                                         
 
                                        
                                                                                   


                               
                                                        

                                       
                                                                                
                                         

                                                                                     
                         


                                                                                                            




                         
                                         
 
                                        
                                                                                   


                               
                                                       

                                       
                                                                                
                                         

                                                                                     
                         


                                                                                                            




                         
                                         
 
                                        
                                                                                   


                               
                                                       



                                                                                     

                                                                                     
                         


                                                                                                            




                         

                                                        
                                                     

                                              
                                                                                               
                                                                     
         
                                         
         
                                                                                 
                                                                       
         
                                              
                 




                                                                             
                                                                                                                                            
                 
                                                                                  
         
                                                                                                      



                              
                                                   

 
                                                                                                               
 
                                                           
                               




                                        
                                                   





                                                          
                                                                                
                                                                                           


                      
                                                                                                                        


                    
                                        
 
                                                                                   

                               









                                                       
                                                                                                                                                                                                 
                                                   
                                                     
                                                                                                                                            
                                                               
                                           
                                                                                                                                               
                                                                                             

 
                                    
 
                                                

                                
                                                                    

 
                                   
 
                                               
                                                      

 
                                     
 
                                      
         
                                    


            
                                   




                                         
                                                        
                                                                                                                        







                                                          
                                                     










                                                
                                                      
                                                                                                                        




                                                 
                                                                                                                        


                                                     
                                                                                               
         
                                                                                  




                           
                                              
 
                                        
                                                                


                                   
                                                                                                

 
                                              
 
                                                          
         



                                                          



                 
                                              
 
                                                          
         



                                                          





                                           
                                                      
                                                                                                                           




                                            
                                                                                                                           





                                                     
                                                                                                    







                       
                                            
 
                                       
         
                                            
                                             




                                         


                                                                      


            
                                                                     


         
                                                       
 
                                                          
                                       
         



                                                                      


            

                                                                   





                                        
                                                   
                                                                                                                        




                                         
                                                        
                                                                                                                        






                                                                                                                                                            
                                                    







































                                                                                                                                                            
                                                   
                                                                                                                        


                    
                                             
 



                                                               

                                                              
                        
                                                          


                                                                             



                                            
                                                                                 



                        
                                                                                 

                                    
                                                                                                                                                                                                                                                                                     

                        
                                                                                                           


            
                                                                                   


         
                                            
 
                                                         
                                                             

 
                                              
 
                                                             
                                                             
         
                                         


            
                                        




                                         
                                                        
                                                                                                                        







                                                          
                                                      


                                                                  
                                                      


                                                                    
                                                      


                                                                      
                                                      


                                                                        
                                                      




                         
                                                        
 

                                                                                                   
                                                            
                                                             
         
                                          


            
                                                





         
                                            
 
                                                     




                                                                  
                                             
 

                                                     
                                                             
                                            
                                                                                    
                                                     






                                         
                                                                                                                               




                            


                                                                                                  

















                                                         
                                                







                                                             
                                                         



                 
                                          
 
                                                   
                                                         

                                                                                                 
                                       


         
                                          
 
              
                                                         



                               
                                                                   

                                                                                                                 
                                                       




                         
                                           
 


                                                     
                                                                
                                                        











                                          

                                                                                                                                                                                                                                                                        
                                

                         
                                         


         
                                          
 
                                                       

 
                                            
 
                                               
         
                                       


            
                                      




                                        
                                                   
                                                                                                                        




                                         
                                                        
                                                                                                                        














                                                                                        
                                                                                 













                                                                                        
                                                                                 













                                                                                        
                                                                                 













                                                                                        
                                                                                 




                      
                                                        

                       
                                                            



             
                            
 
                                           







                            

 
                           
 
                                          
                    

 
                              
 
                     
                                      
                                                     


                    
                                        
 
                                                      
                                          
         
                                    
                 
                                                                                 
                                                      
                 
                                         
                 
                                                                                 
                                                      


                    
                                                                              
                                                   



                 
                             
 
                        
         
                            


            
                                                      
                 
                                                
                 
                                                                                                                          
                 
                                                  









                     
                            
 
                                           


                      

 
                           
 
                                          
                    

 
                                              
 



                              
                                              
                         
                                                                          
                                                 




                              
                                              
                         
                                                                          
                                                 




                              
                                              
                         
                                                                          
                                                 










                                         
                                               















                                                                            
                                                                                      




                               




                                                                     
                                                                                    




                               




                                                                      
                                                                                  
                                  
                                                                                      


                      
                                                                                                                         





                                              
                                                                                                                         






                                                                
                                     















                                                                   
                                     








                                                                     
                                     
                                


                                                                        


















                                               
                                                      
                                                                                                                           




                                            
                                                                                                                           







                                                     
                                                        
                                                                                                                          




                                              
                                                                                                                          







                                                       
                                                      








                                                                                                                                           
                                                                                                                           




                                            
                                                                                                                           







                                                     
                                                      








                                                                                                                                           
                                                                                                                           




                                            
                                                                                                                           







                                                     
                                                          
                                                                                                                          




                                                
                                                                                                                          







                                                         
                                                        
                                                                                                                         




                                              
                                                                                                                         




                                                       
                                                 
 
                     
                                      
                                                                    


                    
                                                             
 
                                                                    
                                      




      
                                               
 
                         















                                                                                    
                                                 















                                                                             
                                








                                                 
                               







                                                 
                            
 
                                                

                                                              

 
                           
 
                                               
                                                      

 
                             
 
                                                 
                                                              



                                        
                                                   








                                                  
                                                                                                                        




                                         
                                                                                                                        













                                                                                             
                                                                                                                                        







                                                                                      
                                                     










                                                             
                                            


                            
                                           





                         
                                                        
 
                                             
                                                     
                                                            




                                      
                                                          
                         
                                                                                  
                                                                                    


                            
                                                                                        
                                                                                   
                                                                                                     
                         
                                                   




                                       
                                                                          
                                                                            

                                                                                    
                         
                                                                                                             
                         
                                                                                               
                         
                                                                                



                         
                                                          

                             
                                             




         
                                    
 
                                                             

                                                                                
                                                




                                                                                                                                                 
                                                                                                                                                                                                                       
                                                                                            

 
                                   
 
                                               
                                                      

 
                                     
 
                                      
         
                                    


            
                                   




                                        
                                                   










                                                           
                                                                                                                        




                                         
                                                        
                                                                                                                        





                                                  
                                                                                














                                                                                                     
                                                             

                                                                     





                         
                                                        
 
                                                     
                                  






                                        
                                                   
                                                                                                                        




                                         
                                                                                                                        







                                                  
                                                   
                                                                                                                        




                                         
                                                                                                                        







                                                  
                                                   
                                                                                                                        




                                         
                                                                                                                        







                                                  
                                                   
                                                                                                                        




                                         
                                                                                                                        




                                                  
                                        
 











                                                                                                                                                               
                                                                                                                       
                                                       




                                        
 



                                     

 



                                                               


















                                                                                                                         
 















                                                                                        
                                
 
                                

 
                                
 
                                

 



                                                                  
 
                                                      
 


                                                                                

                                                                                                                             


                                                                          
 

                                                  




                                                                                                                
 
                                                            
 
                                            
 

                                                                



                                                                
                                                                                                                                  
                                                               
                                                                                                                                  
                                                               
                                                                                                                                  
                                                                 
                                                                                                                                  
                                                                  
                                                                                                                                  


                                                                                                                                                                                   

       
                                                                                                                                                                            
// license:BSD-3-Clause
// copyright-holders:Tim Schuerewegen
/**************************************************************************
 *
 * gp32.cpp - Game Park GP32
 * Driver by Tim Schuerewegen
 *
 * CPU: Samsung S3C2400X01 SoC
 * S3C2400X01 consists of:
 *    ARM920T CPU core + MMU
 *    LCD controller
 *    DMA controller
 *    Interrupt controller
 *    USB controller
 *    and more.
 *
 * TODO:
 * - device-ify s3c240x;
 * - console screen is horizontal, but here screen is setted up with
 *   Height < Width and ROT270, in a double negation fashion. Simplify and
 *   eventually update video fns;
 * - Normalize palette to actual TFT color space;
 * - Several games have dubious sound clipping and mixing;
 * - RF and internet comms & netplay (rallypop has both);
 * - Games from SW list doesn't reload after save, is it even supported?
 * - Add slot for USB PC-Link application, add a host machine connection
 *   somehow;
 * - Verify MP3 support, which in turn needs checking out how the filesystem
 *   works here (and eventually a tool for direct injecting);
 * - Verify gp32linux distro;
 *
 **************************************************************************/

#include "emu.h"
#include "includes/gp32.h"

#include "cpu/arm7/arm7.h"
#include "cpu/arm7/arm7core.h"
#include "sound/volt_reg.h"

#include "softlist.h"
#include "speaker.h"

#define LOG_GENERAL   (1U << 0)
#define LOG_STARTSTOP (1U << 1)
#define LOG_TIMER     (1U << 2)
#define LOG_VRAM      (1U << 3)
#define LOG_MISC      (1U << 4)
#define LOG_TRACE     (1U << 5)

#define VERBOSE LOG_GENERAL

#include "logmacro.h"

#define CLOCK_MULTIPLIER 1

#define MPLLCON  1
#define UPLLCON  2

#define BITS(x,m,n) (((x)>>(n))&((1<<((m)-(n)+1))-1))


// LCD CONTROLLER


#define BPPMODE_TFT_01  0x08
#define BPPMODE_TFT_02  0x09
#define BPPMODE_TFT_04  0x0A
#define BPPMODE_TFT_08  0x0B
#define BPPMODE_TFT_16  0x0C

inline rgb_t gp32_state::s3c240x_get_color_5551( uint16_t data)
{
	uint8_t r, g, b, i;
	r = BITS( data, 15, 11) << 3;
	g = BITS( data, 10, 6) << 3;
	b = BITS( data, 5, 1) << 3;
	i = BIT( data, 1) << 2;
	return rgb_t( r | i, g | i, b | i);
}

void gp32_state::s3c240x_lcd_dma_reload()
{
	m_s3c240x_lcd.vramaddr_cur = m_s3c240x_lcd_regs[5] << 1;
	m_s3c240x_lcd.vramaddr_max = ((m_s3c240x_lcd_regs[5] & 0xFFE00000) | m_s3c240x_lcd_regs[6]) << 1;
	m_s3c240x_lcd.offsize = BITS( m_s3c240x_lcd_regs[7], 21, 11);
	m_s3c240x_lcd.pagewidth_cur = 0;
	m_s3c240x_lcd.pagewidth_max = BITS( m_s3c240x_lcd_regs[7], 10, 0);
	LOGMASKED(LOG_VRAM, "LCD - vramaddr %08X %08X offsize %08X pagewidth %08X\n", m_s3c240x_lcd.vramaddr_cur, m_s3c240x_lcd.vramaddr_max, m_s3c240x_lcd.offsize, m_s3c240x_lcd.pagewidth_max);
}

void gp32_state::s3c240x_lcd_dma_init()
{
	s3c240x_lcd_dma_reload();
	m_s3c240x_lcd.bppmode = BITS( m_s3c240x_lcd_regs[0], 4, 1);
	m_s3c240x_lcd.bswp = BIT( m_s3c240x_lcd_regs[4], 1);
	m_s3c240x_lcd.hwswp = BIT( m_s3c240x_lcd_regs[4], 0);
	m_s3c240x_lcd.lineval = BITS( m_s3c240x_lcd_regs[1], 23, 14);
	m_s3c240x_lcd.hozval = BITS( m_s3c240x_lcd_regs[2], 18, 8);
}

uint32_t gp32_state::s3c240x_lcd_dma_read( )
{
	uint8_t *vram, data[4];
	int i;
	for (i = 0; i < 2; i++)
	{
		vram = (uint8_t *)m_s3c240x_ram.target() + m_s3c240x_lcd.vramaddr_cur - 0x0C000000;
		data[i*2+0] = vram[0];
		data[i*2+1] = vram[1];
		m_s3c240x_lcd.vramaddr_cur += 2;
		m_s3c240x_lcd.pagewidth_cur++;
		if (m_s3c240x_lcd.pagewidth_cur >= m_s3c240x_lcd.pagewidth_max)
		{
			m_s3c240x_lcd.vramaddr_cur += m_s3c240x_lcd.offsize << 1;
			m_s3c240x_lcd.pagewidth_cur = 0;
		}
	}
	if (m_s3c240x_lcd.hwswp == 0)
	{
		if (m_s3c240x_lcd.bswp == 0)
		{
			return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | (data[0] << 0);
		}
		else
		{
			return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3] << 0);
		}
	}
	else
	{
		if (m_s3c240x_lcd.bswp == 0)
		{
			return (data[1] << 24) | (data[0] << 16) | (data[3] << 8) | (data[2] << 0);
		}
		else
		{
			return (data[2] << 24) | (data[3] << 16) | (data[0] << 8) | (data[1] << 0);
		}
	}
}

void gp32_state::s3c240x_lcd_render_01( )
{
	bitmap_rgb32 &bitmap = m_bitmap;
	uint32_t *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
	int i, j;
	for (i = 0; i < 4; i++)
	{
		uint32_t data = s3c240x_lcd_dma_read();
		for (j = 0; j < 32; j++)
		{
			*scanline++ = m_palette->pen_color((data >> 31) & 0x01);
			data = data << 1;
			m_s3c240x_lcd.hpos++;
			if (m_s3c240x_lcd.hpos >= (m_s3c240x_lcd.pagewidth_max << 4))
			{
				m_s3c240x_lcd.vpos = (m_s3c240x_lcd.vpos + 1) % (m_s3c240x_lcd.lineval + 1);
				m_s3c240x_lcd.hpos = 0;
				scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
			}
		}
	}
}

void gp32_state::s3c240x_lcd_render_02( )
{
	bitmap_rgb32 &bitmap = m_bitmap;
	uint32_t *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
	int i, j;
	for (i = 0; i < 4; i++)
	{
		uint32_t data = s3c240x_lcd_dma_read();
		for (j = 0; j < 16; j++)
		{
			*scanline++ = m_palette->pen_color((data >> 30) & 0x03);
			data = data << 2;
			m_s3c240x_lcd.hpos++;
			if (m_s3c240x_lcd.hpos >= (m_s3c240x_lcd.pagewidth_max << 3))
			{
				m_s3c240x_lcd.vpos = (m_s3c240x_lcd.vpos + 1) % (m_s3c240x_lcd.lineval + 1);
				m_s3c240x_lcd.hpos = 0;
				scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
			}
		}
	}
}

void gp32_state::s3c240x_lcd_render_04( )
{
	bitmap_rgb32 &bitmap = m_bitmap;
	uint32_t *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
	int i, j;
	for (i = 0; i < 4; i++)
	{
		uint32_t data = s3c240x_lcd_dma_read( );
		for (j = 0; j < 8; j++)
		{
			*scanline++ = m_palette->pen_color((data >> 28) & 0x0F);
			data = data << 4;
			m_s3c240x_lcd.hpos++;
			if (m_s3c240x_lcd.hpos >= (m_s3c240x_lcd.pagewidth_max << 2))
			{
				m_s3c240x_lcd.vpos = (m_s3c240x_lcd.vpos + 1) % (m_s3c240x_lcd.lineval + 1);
				m_s3c240x_lcd.hpos = 0;
				scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
			}
		}
	}
}

void gp32_state::s3c240x_lcd_render_08( )
{
	bitmap_rgb32 &bitmap = m_bitmap;
	uint32_t *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
	int i, j;
	for (i = 0; i < 4; i++)
	{
		uint32_t data = s3c240x_lcd_dma_read();
		for (j = 0; j < 4; j++)
		{
			*scanline++ = m_palette->pen_color((data >> 24) & 0xFF);
			data = data << 8;
			m_s3c240x_lcd.hpos++;
			if (m_s3c240x_lcd.hpos >= (m_s3c240x_lcd.pagewidth_max << 1))
			{
				m_s3c240x_lcd.vpos = (m_s3c240x_lcd.vpos + 1) % (m_s3c240x_lcd.lineval + 1);
				m_s3c240x_lcd.hpos = 0;
				scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
			}
		}
	}
}

void gp32_state::s3c240x_lcd_render_16( )
{
	bitmap_rgb32 &bitmap = m_bitmap;
	uint32_t *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
	int i, j;
	for (i = 0; i < 4; i++)
	{
		uint32_t data = s3c240x_lcd_dma_read();
		for (j = 0; j < 2; j++)
		{
			*scanline++ = s3c240x_get_color_5551( (data >> 16) & 0xFFFF);
			data = data << 16;
			m_s3c240x_lcd.hpos++;
			if (m_s3c240x_lcd.hpos >= (m_s3c240x_lcd.pagewidth_max << 0))
			{
				m_s3c240x_lcd.vpos = (m_s3c240x_lcd.vpos + 1) % (m_s3c240x_lcd.lineval + 1);
				m_s3c240x_lcd.hpos = 0;
				scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
			}
		}
	}
}

TIMER_CALLBACK_MEMBER(gp32_state::s3c240x_lcd_timer_exp)
{
	LOGMASKED(LOG_TIMER, "LCD timer callback\n");
	m_s3c240x_lcd.vpos = m_screen->vpos();
	m_s3c240x_lcd.hpos = m_screen->hpos();
	LOGMASKED(LOG_VRAM, "LCD - vpos %d hpos %d\n", m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
	if (m_s3c240x_lcd.vramaddr_cur >= m_s3c240x_lcd.vramaddr_max)
	{
		s3c240x_lcd_dma_reload();
	}
	LOGMASKED(LOG_VRAM, "LCD - vramaddr %08X\n", m_s3c240x_lcd.vramaddr_cur);
	while (m_s3c240x_lcd.vramaddr_cur < m_s3c240x_lcd.vramaddr_max)
	{
		switch (m_s3c240x_lcd.bppmode)
		{
			case BPPMODE_TFT_01 : s3c240x_lcd_render_01(); break;
			case BPPMODE_TFT_02 : s3c240x_lcd_render_02(); break;
			case BPPMODE_TFT_04 : s3c240x_lcd_render_04(); break;
			case BPPMODE_TFT_08 : s3c240x_lcd_render_08(); break;
			case BPPMODE_TFT_16 : s3c240x_lcd_render_16(); break;
			default : LOGMASKED(LOG_GENERAL, "s3c240x_lcd_timer_exp: bppmode %d not supported\n", m_s3c240x_lcd.bppmode); break;
		}
		if ((m_s3c240x_lcd.vpos == 0) && (m_s3c240x_lcd.hpos == 0)) break;
	}
	m_s3c240x_lcd_timer->adjust(m_screen->time_until_pos(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos));
}

void gp32_state::video_start()
{
	m_screen->register_screen_bitmap(m_bitmap);
}

uint32_t gp32_state::screen_update_gp32(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
	copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
	s3c240x_lcd_dma_init();
	return 0;
}

READ32_MEMBER(gp32_state::s3c240x_lcd_r)
{
	uint32_t data = m_s3c240x_lcd_regs[offset];
	switch (offset)
	{
		// LCDCON1
		case 0x00 / 4 :
		{
			// make sure line counter is going
			uint32_t lineval = BITS( m_s3c240x_lcd_regs[1], 23, 14);
			data = (data & ~0xFFFC0000) | ((lineval - m_screen->vpos()) << 18);
		}
		break;
	}
	LOGMASKED(LOG_TRACE, "(LCD) %08X -> %08X %s\n", 0x14A00000 + (offset << 2), data, machine().describe_context());
	return data;
}

void gp32_state::s3c240x_lcd_configure()
{
	uint32_t vspw, vbpd, lineval, vfpd, hspw, hbpd, hfpd, hozval, clkval, hclk;
	double framerate, vclk;
	rectangle visarea;
	vspw = BITS( m_s3c240x_lcd_regs[1], 5, 0);
	vbpd = BITS( m_s3c240x_lcd_regs[1], 31, 24);
	lineval = BITS( m_s3c240x_lcd_regs[1], 23, 14);
	vfpd = BITS( m_s3c240x_lcd_regs[1], 13, 6);
	hspw = BITS( m_s3c240x_lcd_regs[3], 7, 0);
	hbpd = BITS( m_s3c240x_lcd_regs[2], 25, 19);
	hfpd = BITS( m_s3c240x_lcd_regs[2], 7, 0);
	hozval = BITS( m_s3c240x_lcd_regs[2], 18, 8);
	clkval = BITS( m_s3c240x_lcd_regs[0], 17, 8);
	hclk = s3c240x_get_hclk(MPLLCON);
	LOGMASKED(LOG_VRAM, "LCD - vspw %d vbpd %d lineval %d vfpd %d hspw %d hbpd %d hfpd %d hozval %d clkval %d hclk %d\n", vspw, vbpd, lineval, vfpd, hspw, hbpd, hfpd, hozval, clkval, hclk);
	vclk = (double)(hclk / ((clkval + 1) * 2));
	LOGMASKED(LOG_VRAM, "LCD - vclk %f\n", vclk);
	framerate = vclk / (((vspw + 1) + (vbpd + 1) + (lineval + 1) + (vfpd + 1)) * ((hspw + 1) + (hbpd + 1) + (hfpd + 1) + (hozval + 1)));
	LOGMASKED(LOG_VRAM, "LCD - framerate %f\n", framerate);
	visarea.set(0, hozval, 0, lineval);
	LOGMASKED(LOG_VRAM, "LCD - visarea min_x %d min_y %d max_x %d max_y %d\n", visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y);
	m_screen->configure(hozval + 1, lineval + 1, visarea, HZ_TO_ATTOSECONDS( framerate));
}

void gp32_state::s3c240x_lcd_start()
{
	LOGMASKED(LOG_STARTSTOP, "LCD start\n");
	s3c240x_lcd_configure();
	s3c240x_lcd_dma_init();
	m_s3c240x_lcd_timer->adjust(m_screen->time_until_pos(0, 0));
}

void gp32_state::s3c240x_lcd_stop()
{
	LOGMASKED(LOG_STARTSTOP, "LCD stop\n");
	m_s3c240x_lcd_timer->adjust( attotime::never);
}

void gp32_state::s3c240x_lcd_recalc()
{
	if (m_s3c240x_lcd_regs[0] & 1)
	{
		s3c240x_lcd_start();
	}
	else
	{
		s3c240x_lcd_stop();
	}
}

WRITE32_MEMBER(gp32_state::s3c240x_lcd_w)
{
	uint32_t old_value = m_s3c240x_lcd_regs[offset];
	LOGMASKED(LOG_TRACE, "(LCD) %08X <- %08X %s\n", 0x14A00000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_lcd_regs[offset]);
	switch (offset)
	{
		// LCDCON1
		case 0x00 / 4 :
		{
			if ((old_value & 1) != (data & 1))
			{
				s3c240x_lcd_recalc();
			}
		}
		break;
	}
}

// LCD PALETTE


READ32_MEMBER(gp32_state::s3c240x_lcd_palette_r)
{
	uint32_t data = m_s3c240x_lcd_palette[offset];
	LOGMASKED(LOG_TRACE, "(LCD) %08X -> %08X %s\n", 0x14A00400 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_lcd_palette_w)
{
	LOGMASKED(LOG_TRACE, "(LCD) %08X <- %08X %s\n", 0x14A00400 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_lcd_palette[offset]);
	if (mem_mask != 0xffffffff)
	{
		LOGMASKED(LOG_GENERAL, "s3c240x_lcd_palette_w: unknown mask %08x\n", mem_mask);
	}
	m_palette->set_pen_color( offset, s3c240x_get_color_5551( data & 0xFFFF));
}

// CLOCK & POWER MANAGEMENT


uint32_t gp32_state::s3c240x_get_fclk(int reg)
{
	uint32_t data, mdiv, pdiv, sdiv;
	data = m_s3c240x_clkpow_regs[reg]; // MPLLCON or UPLLCON
	mdiv = BITS( data, 19, 12);
	pdiv = BITS( data, 9, 4);
	sdiv = BITS( data, 1, 0);
	return (uint32_t)((double)((mdiv + 8) * 12000000) / (double)((pdiv + 2) * (1 << sdiv)));
}

uint32_t gp32_state::s3c240x_get_hclk(int reg)
{
	switch (m_s3c240x_clkpow_regs[5] & 0x3) // CLKDIVN
	{
		case 0 : return s3c240x_get_fclk(reg) / 1;
		case 1 : return s3c240x_get_fclk(reg) / 1;
		case 2 : return s3c240x_get_fclk(reg) / 2;
		case 3 : return s3c240x_get_fclk(reg) / 2;
	}
	return 0;
}

uint32_t gp32_state::s3c240x_get_pclk(int reg)
{
	switch (m_s3c240x_clkpow_regs[5] & 0x3) // CLKDIVN
	{
		case 0 : return s3c240x_get_fclk(reg) / 1;
		case 1 : return s3c240x_get_fclk(reg) / 2;
		case 2 : return s3c240x_get_fclk(reg) / 2;
		case 3 : return s3c240x_get_fclk(reg) / 4;
	}
	return 0;
}

READ32_MEMBER(gp32_state::s3c240x_clkpow_r)
{
	uint32_t data = m_s3c240x_clkpow_regs[offset];
	LOGMASKED(LOG_TRACE, "(CLKPOW) %08X -> %08X %s\n", 0x14800000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_clkpow_w)
{
	LOGMASKED(LOG_TRACE, "(CLKPOW) %08X <- %08X %s\n", 0x14800000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_clkpow_regs[offset]);
	switch (offset)
	{
		// MPLLCON
		case 0x04 / 4 :
		{
			m_maincpu->set_unscaled_clock(s3c240x_get_fclk(MPLLCON) * CLOCK_MULTIPLIER);
		}
		break;
	}
}

// INTERRUPT CONTROLLER


void gp32_state::s3c240x_check_pending_irq()
{
	if (m_s3c240x_irq_regs[0] != 0)
	{
		uint32_t int_type = 0, temp;
		temp = m_s3c240x_irq_regs[0];
		while (!(temp & 1))
		{
			int_type++;
			temp = temp >> 1;
		}
		m_s3c240x_irq_regs[4] |= (1 << int_type); // INTPND
		m_s3c240x_irq_regs[5] = int_type; // INTOFFSET
		m_maincpu->set_input_line(ARM7_IRQ_LINE, ASSERT_LINE);
	}
	else
	{
		m_maincpu->set_input_line(ARM7_IRQ_LINE, CLEAR_LINE);
	}
}

void gp32_state::s3c240x_request_irq(uint32_t int_type)
{
	LOGMASKED(LOG_MISC, "request irq %d\n", int_type);
	if (m_s3c240x_irq_regs[0] == 0)
	{
		m_s3c240x_irq_regs[0] |= (1 << int_type); // SRCPND
		m_s3c240x_irq_regs[4] |= (1 << int_type); // INTPND
		m_s3c240x_irq_regs[5] = int_type; // INTOFFSET
		m_maincpu->set_input_line(ARM7_IRQ_LINE, ASSERT_LINE);
	}
	else
	{
		m_s3c240x_irq_regs[0] |= (1 << int_type); // SRCPND
		s3c240x_check_pending_irq();
	}
}


READ32_MEMBER(gp32_state::s3c240x_irq_r)
{
	uint32_t data = m_s3c240x_irq_regs[offset];
	LOGMASKED(LOG_TRACE, "(IRQ) %08X -> %08X %s\n", 0x14400000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_irq_w)
{
	uint32_t old_value = m_s3c240x_irq_regs[offset];
	LOGMASKED(LOG_TRACE, "(IRQ) %08X <- %08X %s\n", 0x14400000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_irq_regs[offset]);
	switch (offset)
	{
		// SRCPND
		case 0x00 / 4 :
		{
			m_s3c240x_irq_regs[0] = (old_value & ~data); // clear only the bit positions of SRCPND corresponding to those set to one in the data
			s3c240x_check_pending_irq();
		}
		break;
		// INTPND
		case 0x10 / 4 :
		{
			m_s3c240x_irq_regs[4] = (old_value & ~data); // clear only the bit positions of INTPND corresponding to those set to one in the data
		}
		break;
	}
}

// PWM TIMER

#if 0
static const char *const timer_reg_names[] =
{
	"Timer config 0",
	"Timer config 1",
	"Timer control",
	"Timer count buffer 0",
	"Timer compare buffer 0",
	"Timer count observation 0",
	"Timer count buffer 1",
	"Timer compare buffer 1",
	"Timer count observation 1",
	"Timer count buffer 2",
	"Timer compare buffer 2",
	"Timer count observation 2",
	"Timer count buffer 3",
	"Timer compare buffer 3",
	"Timer count observation 3",
	"Timer count buffer 4",
	"Timer compare buffer 4",
	"Timer count observation 4",
};
#endif


READ32_MEMBER(gp32_state::s3c240x_pwm_r)
{
	uint32_t data = m_s3c240x_pwm_regs[offset];
	LOGMASKED(LOG_TRACE, "(PWM) %08X -> %08X %s\n", 0x15100000 + (offset << 2), data, machine().describe_context());
	return data;
}

void gp32_state::s3c240x_pwm_start(int timer)
{
	static const int mux_table[] = { 2, 4, 8, 16 };
	static const int prescaler_shift[] = { 0, 0, 8, 8, 8 };
	static const int mux_shift[] = { 0, 4, 8, 12, 16 };
	static const int tcon_shift[] = { 0, 8, 12, 16, 20 };
	const uint32_t *regs = &m_s3c240x_pwm_regs[3+timer*3];
	uint32_t prescaler, mux, cnt, cmp, auto_reload;
	double freq, hz;
	LOGMASKED(LOG_STARTSTOP, "PWM %d start\n", timer);
	prescaler = (m_s3c240x_pwm_regs[0] >> prescaler_shift[timer]) & 0xFF;
	mux = (m_s3c240x_pwm_regs[1] >> mux_shift[timer]) & 0x0F;
	freq = s3c240x_get_pclk(MPLLCON) / (prescaler + 1) / mux_table[mux];
	cnt = BITS( regs[0], 15, 0);
	if (timer != 4)
	{
		cmp = BITS( regs[1], 15, 0);
		auto_reload = BIT( m_s3c240x_pwm_regs[2], tcon_shift[timer] + 3);
	}
	else
	{
		cmp = 0;
		auto_reload = BIT( m_s3c240x_pwm_regs[2], tcon_shift[timer] + 2);
	}
	hz = freq / (cnt - cmp + 1);
	LOGMASKED(LOG_MISC, "PWM %d - FCLK=%d HCLK=%d PCLK=%d prescaler=%d div=%d freq=%f cnt=%d cmp=%d auto_reload=%d hz=%f\n", timer, s3c240x_get_fclk(MPLLCON), s3c240x_get_hclk(MPLLCON), s3c240x_get_pclk(MPLLCON), prescaler, mux_table[mux], freq, cnt, cmp, auto_reload, hz);
	if (auto_reload)
	{
		m_s3c240x_pwm_timer[timer]->adjust( attotime::from_hz( hz), timer, attotime::from_hz( hz));
	}
	else
	{
		m_s3c240x_pwm_timer[timer]->adjust( attotime::from_hz( hz), timer);
	}
}

void gp32_state::s3c240x_pwm_stop(int timer)
{
	LOGMASKED(LOG_STARTSTOP, "PWM %d stop\n", timer);
	m_s3c240x_pwm_timer[timer]->adjust( attotime::never);
}

void gp32_state::s3c240x_pwm_recalc(int timer)
{
	static const int tcon_shift[] = { 0, 8, 12, 16, 20 };
	if (m_s3c240x_pwm_regs[2] & (1 << tcon_shift[timer]))
	{
		s3c240x_pwm_start(timer);
	}
	else
	{
		s3c240x_pwm_stop(timer);
	}
}

WRITE32_MEMBER(gp32_state::s3c240x_pwm_w)
{
	uint32_t old_value = m_s3c240x_pwm_regs[offset];
	LOGMASKED(LOG_TRACE, "(PWM) %08X <- %08X %s\n", 0x15100000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_pwm_regs[offset]);
	switch (offset)
	{
		// TCON
		case 0x08 / 4 :
		{
			if ((data & 1) != (old_value & 1))
			{
				s3c240x_pwm_recalc(0);
			}
			if ((data & 0x100) != (old_value & 0x100))
			{
				s3c240x_pwm_recalc(1);
			}
			if ((data & 0x1000) != (old_value & 0x1000))
			{
				s3c240x_pwm_recalc(2);
			}
			if ((data & 0x10000) != (old_value & 0x10000))
			{
				s3c240x_pwm_recalc(3);
			}
			if ((data & 0x100000) != (old_value & 0x100000))
			{
				s3c240x_pwm_recalc(4);
			}
		}
	}
}

TIMER_CALLBACK_MEMBER(gp32_state::s3c240x_pwm_timer_exp)
{
	int ch = param;
	static const int ch_int[] = { INT_TIMER0, INT_TIMER1, INT_TIMER2, INT_TIMER3, INT_TIMER4 };
	LOGMASKED(LOG_TIMER, "PWM %d timer callback\n", ch);
	if (BITS( m_s3c240x_pwm_regs[1], 23, 20) == (ch + 1))
	{
		s3c240x_dma_request_pwm();
	}
	else
	{
		s3c240x_request_irq(ch_int[ch]);
	}
}

// DMA


void gp32_state::s3c240x_dma_reload(int dma)
{
	uint32_t *regs = &m_s3c240x_dma_regs[dma<<3];
	regs[3] = (regs[3] & ~0x000FFFFF) | BITS( regs[2], 19, 0);
	regs[4] = (regs[4] & ~0x1FFFFFFF) | BITS( regs[0], 28, 0);
	regs[5] = (regs[5] & ~0x1FFFFFFF) | BITS( regs[1], 28, 0);
}

void gp32_state::s3c240x_dma_trigger(int dma)
{
	uint32_t *regs = &m_s3c240x_dma_regs[dma<<3];
	uint32_t curr_tc, curr_src, curr_dst;
	address_space &space = m_maincpu->space( AS_PROGRAM);
	int dsz, inc_src, inc_dst, servmode;
	static const uint32_t ch_int[] = { INT_DMA0, INT_DMA1, INT_DMA2, INT_DMA3 };
	LOGMASKED(LOG_MISC, "DMA %d trigger\n", dma);
	curr_tc = BITS( regs[3], 19, 0);
	curr_src = BITS( regs[4], 28, 0);
	curr_dst = BITS( regs[5], 28, 0);
	dsz = BITS( regs[2], 21, 20);
	servmode = BIT( regs[2], 26);
	inc_src = BIT( regs[0], 29);
	inc_dst = BIT( regs[1], 29);
	LOGMASKED(LOG_MISC, "DMA %d - curr_src %08X curr_dst %08X curr_tc %d dsz %d\n", dma, curr_src, curr_dst, curr_tc, dsz);
	while (curr_tc > 0)
	{
		curr_tc--;
		switch (dsz)
		{
			case 0 : space.write_byte( curr_dst, space.read_byte( curr_src)); break;
			case 1 : space.write_word( curr_dst, space.read_word( curr_src)); break;
			case 2 : space.write_dword( curr_dst, space.read_dword( curr_src)); break;
		}
		if (inc_src == 0) curr_src += (1 << dsz);
		if (inc_dst == 0) curr_dst += (1 << dsz);
		if (servmode == 0) break;
	}
	// update curr_src
	regs[4] = (regs[4] & ~0x1FFFFFFF) | curr_src;
	// update curr_dst
	regs[5] = (regs[5] & ~0x1FFFFFFF) | curr_dst;
	// update curr_tc
	regs[3] = (regs[3] & ~0x000FFFFF) | curr_tc;
	// ...
	if (curr_tc == 0)
	{
		int _int, reload;
		reload = BIT( regs[2], 22);
		if (!reload)
		{
			s3c240x_dma_reload(dma);
		}
		else
		{
			regs[6] &= ~(1 << 1); // clear on/off
		}
		_int = BIT( regs[2], 28);
		if (_int)
		{
			s3c240x_request_irq(ch_int[dma]);
		}
	}
}

void gp32_state::s3c240x_dma_request_iis()
{
	uint32_t *regs = &m_s3c240x_dma_regs[2<<3];
	LOGMASKED(LOG_MISC, "s3c240x_dma_request_iis\n");
	if ((BIT( regs[6], 1) != 0) && (BIT( regs[2], 23) != 0) && (BITS( regs[2], 25, 24) == 0))
	{
		s3c240x_dma_trigger(2);
	}
}

void gp32_state::s3c240x_dma_request_pwm()
{
	int i;
	LOGMASKED(LOG_MISC, "s3c240x_dma_request_pwm\n");
	for (i = 0; i < 4; i++)
	{
		if (i != 1)
		{
			uint32_t *regs = &m_s3c240x_dma_regs[i<<3];
			if ((BIT( regs[6], 1) != 0) && (BIT( regs[2], 23) != 0) && (BITS( regs[2], 25, 24) == 3))
			{
				s3c240x_dma_trigger(i);
			}
		}
	}
}

void gp32_state::s3c240x_dma_start(int dma)
{
	uint32_t addr_src, addr_dst, tc;
	uint32_t *regs = &m_s3c240x_dma_regs[dma<<3];
	uint32_t dsz, tsz, reload;
	int inc_src, inc_dst, _int, servmode, swhwsel, hwsrcsel;
	LOGMASKED(LOG_STARTSTOP, "DMA %d start\n", dma);
	addr_src = BITS( regs[0], 28, 0);
	addr_dst = BITS( regs[1], 28, 0);
	tc = BITS( regs[2], 19, 0);
	inc_src = BIT( regs[0], 29);
	inc_dst = BIT( regs[1], 29);
	tsz = BIT( regs[2], 27);
	_int = BIT( regs[2], 28);
	servmode = BIT( regs[2], 26);
	hwsrcsel = BITS( regs[2], 25, 24);
	swhwsel = BIT( regs[2], 23);
	reload = BIT( regs[2], 22);
	dsz = BITS( regs[2], 21, 20);
	LOGMASKED(LOG_MISC, "DMA %d - addr_src %08X inc_src %d addr_dst %08X inc_dst %d int %d tsz %d servmode %d hwsrcsel %d swhwsel %d reload %d dsz %d tc %d\n", dma, addr_src, inc_src, addr_dst, inc_dst, _int, tsz, servmode, hwsrcsel, swhwsel, reload, dsz, tc);
	LOGMASKED(LOG_MISC, "DMA %d - copy %08X bytes from %08X (%s) to %08X (%s)\n", dma, tc << dsz, addr_src, inc_src ? "fix" : "inc", addr_dst, inc_dst ? "fix" : "inc");
	s3c240x_dma_reload(dma);
	if (swhwsel == 0)
	{
		s3c240x_dma_trigger(dma);
	}
}

void gp32_state::s3c240x_dma_stop(int dma)
{
	LOGMASKED(LOG_STARTSTOP, "DMA %d stop\n", dma);
}

void gp32_state::s3c240x_dma_recalc(int dma)
{
	if (m_s3c240x_dma_regs[(dma<<3)+6] & 2)
	{
		s3c240x_dma_start(dma);
	}
	else
	{
		s3c240x_dma_stop(dma);
	}
}

READ32_MEMBER(gp32_state::s3c240x_dma_r)
{
	uint32_t data = m_s3c240x_dma_regs[offset];
	LOGMASKED(LOG_TRACE, "(DMA) %08X -> %08X %s\n", 0x14600000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_dma_w)
{
	uint32_t old_value = m_s3c240x_dma_regs[offset];
	LOGMASKED(LOG_TRACE, "(DMA) %08X <- %08X %s\n", 0x14600000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_dma_regs[offset]);
	switch (offset)
	{
		// DCON0
		case 0x08 / 4 :
		{
			if (((data >> 22) & 1) != 0) // reload
			{
				m_s3c240x_dma_regs[0x18/4] &= ~(1 << 1); // clear on/off
			}
		}
		break;
		// DMASKTRIG0
		case 0x18 / 4 :
		{
			if ((old_value & 2) != (data & 2)) s3c240x_dma_recalc(0);
		}
		break;
		// DCON1
		case 0x28 / 4 :
		{
			if (((data >> 22) & 1) != 0) // reload
			{
				m_s3c240x_dma_regs[0x38/4] &= ~(1 << 1); // clear on/off
			}
		}
		break;
		// DMASKTRIG1
		case 0x38 / 4 :
		{
			if ((old_value & 2) != (data & 2)) s3c240x_dma_recalc(1);
		}
		break;
		// DCON2
		case 0x48 / 4 :
		{
			if (((data >> 22) & 1) != 0) // reload
			{
				m_s3c240x_dma_regs[0x58/4] &= ~(1 << 1); // clear on/off
			}
		}
		break;
		// DMASKTRIG2
		case 0x58 / 4 :
		{
			if ((old_value & 2) != (data & 2)) s3c240x_dma_recalc(2);
		}
		break;
		// DCON3
		case 0x68 / 4 :
		{
			if (((data >> 22) & 1) != 0) // reload
			{
				m_s3c240x_dma_regs[0x78/4] &= ~(1 << 1); // clear on/off
			}
		}
		break;
		// DMASKTRIG3
		case 0x78 / 4 :
		{
			if ((old_value & 2) != (data & 2)) s3c240x_dma_recalc(3);
		}
		break;
	}
}

TIMER_CALLBACK_MEMBER(gp32_state::s3c240x_dma_timer_exp)
{
	int ch = param;
	LOGMASKED(LOG_TIMER, "DMA %d timer callback\n", ch);
}

// SMARTMEDIA

void gp32_state::smc_reset()
{
	LOGMASKED(LOG_MISC, "smc_reset\n");
	m_smc.add_latch = 0;
	m_smc.chip = 0;
	m_smc.cmd_latch = 0;
	m_smc.do_read = 0;
	m_smc.do_write = 0;
	m_smc.read = 0;
	m_smc.wp = 0;
	m_smc.busy = 0;
}

void gp32_state::smc_init()
{
	LOGMASKED(LOG_MISC, "smc_init\n");
	smc_reset();
}

uint8_t gp32_state::smc_read()
{
	uint8_t data;
	data = m_smartmedia->data_r();
	LOGMASKED(LOG_MISC, "smc_read %08X\n", data);
	return data;
}

void gp32_state::smc_write(uint8_t data)
{
	LOGMASKED(LOG_MISC, "smc_write %08X\n", data);
	if ((m_smc.chip) && (!m_smc.read))
	{
		if (m_smc.cmd_latch)
		{
			LOGMASKED(LOG_MISC, "smartmedia_command_w %08X\n", data);
			m_smartmedia->command_w(data);
		}
		else if (m_smc.add_latch)
		{
			LOGMASKED(LOG_MISC, "smartmedia_address_w %08X\n", data);
			m_smartmedia->address_w(data);
		}
		else
		{
			LOGMASKED(LOG_MISC, "smartmedia_data_w %08X\n", data);
			m_smartmedia->data_w(data);
		}
	}
}

void gp32_state::smc_update()
{
	if (!m_smc.chip)
	{
		smc_reset();
	}
	else
	{
		if ((m_smc.do_write) && (!m_smc.read))
		{
			smc_write(m_smc.datatx);
		}
		else if ((!m_smc.do_write) && (m_smc.do_read) && (m_smc.read) && (!m_smc.cmd_latch) && (!m_smc.add_latch))
		{
			m_smc.datarx = smc_read();
		}
	}
}

// I2S

#define I2S_L3C ( 1 )
#define I2S_L3M ( 2 )
#define I2S_L3D ( 3 )

void gp32_state::i2s_reset()
{
	LOGMASKED(LOG_MISC, "i2s_reset\n");
	m_i2s.l3d = 0;
	m_i2s.l3m = 0;
	m_i2s.l3c = 0;
}

void gp32_state::i2s_init()
{
	LOGMASKED(LOG_MISC, "i2s_init\n");
	i2s_reset();
}

void gp32_state::i2s_write(int line, int data)
{
	switch (line)
	{
		case I2S_L3C :
		{
			if (data != m_i2s.l3c)
			{
				LOGMASKED(LOG_MISC, "I2S L3C %d\n", data);
				m_i2s.l3c = data;
			}
		}
		break;
		case I2S_L3M :
		{
			if (data != m_i2s.l3m)
			{
				LOGMASKED(LOG_MISC, "I2S L3M %d\n", data);
				m_i2s.l3m = data;
			}
		}
		break;
		case I2S_L3D :
		{
			if (data != m_i2s.l3d)
			{
				LOGMASKED(LOG_MISC, "I2S L3D %d\n", data);
				m_i2s.l3d = data;
			}
		}
		break;
	}
}

// I/O PORT


READ32_MEMBER(gp32_state::s3c240x_gpio_r)
{
	uint32_t data = m_s3c240x_gpio[offset];
	switch (offset)
	{
		// PBCON
		case 0x08 / 4 :
		{
			// smartmedia
			data = (data & ~0x00000001);
			if (!m_smc.read) data = data | 0x00000001;
		}
		break;
		// PBDAT
		case 0x0C / 4 :
		{
			// smartmedia
			data = (data & ~0x000000FF) | (m_smc.datarx & 0xFF);
			// buttons
			data = (data & ~0x0000FF00) | (m_io_in0->read() & 0x0000FF00);
		}
		break;
		// PDDAT
		case 0x24 / 4 :
		{
			// smartmedia
			data = (data & ~0x000003C0);
			if (!m_smc.busy) data = data | 0x00000200;
			if (!m_smc.do_read) data = data | 0x00000100;
			if (!m_smc.chip) data = data | 0x00000080;
			if (!m_smartmedia->is_protected()) data = data | 0x00000040;
		}
		break;
		// PEDAT
		case 0x30 / 4 :
		{
			// smartmedia
			data = (data & ~0x0000003C);
			if (m_smc.cmd_latch) data = data | 0x00000020;
			if (m_smc.add_latch) data = data | 0x00000010;
			if (!m_smc.do_write) data = data | 0x00000008;
			if (!m_smartmedia->is_present()) data = data | 0x00000004;
			// buttons
			data = (data & ~0x000000C0) | (m_io_in1->read() & 0x000000C0);
		}
		break;
	}
	LOGMASKED(LOG_TRACE, "(GPIO) %08X -> %08X %s\n", 0x15600000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_gpio_w)
{
	COMBINE_DATA(&m_s3c240x_gpio[offset]);
	LOGMASKED(LOG_TRACE, "(GPIO) %08X <- %08X %s\n", 0x15600000 + (offset << 2), data, machine().describe_context());
	switch (offset)
	{
		// PBCON
		case 0x08 / 4 :
		{
			// smartmedia
			m_smc.read = ((data & 0x00000001) == 0);
			smc_update();
		}
		break;
		// PBDAT
		case 0x0C / 4 :
		{
			// smartmedia
			m_smc.datatx = data & 0xFF;
		}
		break;
		// PDDAT
		case 0x24 / 4 :
		{
			// smartmedia
			m_smc.do_read = ((data & 0x00000100) == 0);
			m_smc.chip = ((data & 0x00000080) == 0);
			m_smc.wp = ((data & 0x00000040) == 0);
			smc_update();
		}
		break;
		// PEDAT
		case 0x30 / 4 :
		{
			// smartmedia
			m_smc.cmd_latch = ((data & 0x00000020) != 0);
			m_smc.add_latch = ((data & 0x00000010) != 0);
			m_smc.do_write = ((data & 0x00000008) == 0);
			smc_update();
			// sound
			i2s_write(I2S_L3D, (data & 0x00000800) ? 1 : 0);
			i2s_write(I2S_L3M, (data & 0x00000400) ? 1 : 0);
			i2s_write(I2S_L3C, (data & 0x00000200) ? 1 : 0);
		}
		break;
#if 0
		// PGDAT
		case 0x48 / 4 :
		{
			int i2ssdo;
			i2ssdo = BIT( data, 3);
		}
		break;
#endif
	}
}

// MEMORY CONTROLLER


READ32_MEMBER(gp32_state::s3c240x_memcon_r)
{
	uint32_t data = m_s3c240x_memcon_regs[offset];
	LOGMASKED(LOG_TRACE, "(MEMCON) %08X -> %08X %s\n", 0x14000000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_memcon_w)
{
	LOGMASKED(LOG_TRACE, "(MEMCON) %08X <- %08X %s\n", 0x14000000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_memcon_regs[offset]);
}

// USB HOST CONTROLLER


READ32_MEMBER(gp32_state::s3c240x_usb_host_r)
{
	uint32_t data = m_s3c240x_usb_host_regs[offset];
	LOGMASKED(LOG_TRACE, "(USB H) %08X -> %08X %s\n", 0x14200000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_usb_host_w)
{
	LOGMASKED(LOG_TRACE, "(USB H) %08X <- %08X %s\n", 0x14200000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_usb_host_regs[offset]);
}

// UART 0


READ32_MEMBER(gp32_state::s3c240x_uart_0_r)
{
	uint32_t data = m_s3c240x_uart_0_regs[offset];
	switch (offset)
	{
		// UTRSTAT0
		case 0x10 / 4 :
		{
			data = (data & ~0x00000006) | 0x00000004 | 0x00000002; // [bit 2] Transmitter empty / [bit 1] Transmit buffer empty
		}
		break;
	}
	LOGMASKED(LOG_TRACE, "(UART 0) %08X -> %08X %s\n", 0x15000000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_uart_0_w)
{
	LOGMASKED(LOG_TRACE, "(UART 0) %08X <- %08X %s\n", 0x15000000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_uart_0_regs[offset]);
}

// UART 1


READ32_MEMBER(gp32_state::s3c240x_uart_1_r)
{
	uint32_t data = m_s3c240x_uart_1_regs[offset];
	switch (offset)
	{
		// UTRSTAT1
		case 0x10 / 4 :
		{
			data = (data & ~0x00000006) | 0x00000004 | 0x00000002; // [bit 2] Transmitter empty / [bit 1] Transmit buffer empty
		}
		break;
	}
	LOGMASKED(LOG_TRACE, "(UART 1) %08X -> %08X %s\n", 0x15004000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_uart_1_w)
{
	LOGMASKED(LOG_TRACE, "(UART 1) %08X <- %08X %s\n", 0x15004000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_uart_1_regs[offset]);
}

// USB DEVICE


READ32_MEMBER(gp32_state::s3c240x_usb_device_r)
{
	uint32_t data = m_s3c240x_usb_device_regs[offset];
	LOGMASKED(LOG_TRACE, "(USB D) %08X -> %08X %s\n", 0x15200140 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_usb_device_w)
{
	LOGMASKED(LOG_TRACE, "(USB D) %08X <- %08X %s\n", 0x15200140 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_usb_device_regs[offset]);
}

// WATCHDOG TIMER


READ32_MEMBER(gp32_state::s3c240x_watchdog_r)
{
	uint32_t data = m_s3c240x_watchdog_regs[offset];
	LOGMASKED(LOG_TRACE, "(WDOG) %08X -> %08X %s\n", 0x15300000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_watchdog_w)
{
	LOGMASKED(LOG_TRACE, "(WDOG) %08X <- %08X %s\n", 0x15300000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_watchdog_regs[offset]);
}

// EEPROM

uint8_t gp32_state::eeprom_read(uint16_t address)
{
	uint8_t data;
	data = m_eeprom_data[address];
	LOGMASKED(LOG_MISC, "EEPROM %04X -> %02X\n", address, data);
	return data;
}

void gp32_state::eeprom_write(uint16_t address, uint8_t data)
{
	LOGMASKED(LOG_MISC, "EEPROM %04X <- %02X\n", address, data);
	m_eeprom_data[address] = data;
}

// IIC

#if 0
uint8_t gp32_state::i2cmem_read_byte( int last)
{
	uint8_t data = 0;
	int i;
	i2cmem_write( machine, 0, I2CMEM_SDA, 1);
	for (i = 0; i < 8; i++)
	{
		i2cmem_write( machine, 0, I2CMEM_SCL, 1);
		data = (data << 1) + (i2cmem_read( machine, 0, I2CMEM_SDA) ? 1 : 0);
		i2cmem_write( machine, 0, I2CMEM_SCL, 0);
	}
	i2cmem_write( machine, 0, I2CMEM_SDA, last);
	i2cmem_write( machine, 0, I2CMEM_SCL, 1);
	i2cmem_write( machine, 0, I2CMEM_SCL, 0);
	return data;
}
#endif

#if 0
void gp32_state::i2cmem_write_byte( uint8_t data)
{
	int i;
	for (i = 0; i < 8; i++)
	{
		i2cmem_write( machine, 0, I2CMEM_SDA, (data & 0x80) ? 1 : 0);
		data = data << 1;
		i2cmem_write( machine, 0, I2CMEM_SCL, 1);
		i2cmem_write( machine, 0, I2CMEM_SCL, 0);
	}
	i2cmem_write( machine, 0, I2CMEM_SDA, 1); // ack bit
	i2cmem_write( machine, 0, I2CMEM_SCL, 1);
	i2cmem_write( machine, 0, I2CMEM_SCL, 0);
}
#endif

#if 0
void gp32_state::i2cmem_start( )
{
	i2cmem_write( machine, 0, I2CMEM_SDA, 1);
	i2cmem_write( machine, 0, I2CMEM_SCL, 1);
	i2cmem_write( machine, 0, I2CMEM_SDA, 0);
	i2cmem_write( machine, 0, I2CMEM_SCL, 0);
}
#endif

#if 0
void gp32_state::i2cmem_stop( )
{
	i2cmem_write( machine, 0, I2CMEM_SDA, 0);
	i2cmem_write( machine, 0, I2CMEM_SCL, 1);
	i2cmem_write( machine, 0, I2CMEM_SDA, 1);
	i2cmem_write( machine, 0, I2CMEM_SCL, 0);
}
#endif

void gp32_state::iic_start()
{
	LOGMASKED(LOG_STARTSTOP, "IIC start\n");
	m_s3c240x_iic.data_index = 0;
	m_s3c240x_iic_timer->adjust( attotime::from_msec( 1));
}

void gp32_state::iic_stop()
{
	LOGMASKED(LOG_STARTSTOP, "IIC stop\n");
	m_s3c240x_iic_timer->adjust( attotime::never);
}

void gp32_state::iic_resume()
{
	LOGMASKED(LOG_STARTSTOP, "IIC resume\n");
	m_s3c240x_iic_timer->adjust( attotime::from_msec( 1));
}

READ32_MEMBER(gp32_state::s3c240x_iic_r)
{
	uint32_t data = m_s3c240x_iic_regs[offset];
	switch (offset)
	{
		// IICSTAT
		case 0x04 / 4 :
		{
			data = data & ~0x0000000F;
		}
		break;
	}
	LOGMASKED(LOG_TRACE, "(IIC) %08X -> %08X %s\n", 0x15400000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_iic_w)
{
	LOGMASKED(LOG_TRACE, "(IIC) %08X <- %08X %s\n", 0x15400000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_iic_regs[offset]);
	switch (offset)
	{
		// ADDR_IICCON
		case 0x00 / 4 :
		{
			int interrupt_pending_flag;
#if 0
			static const int div_table[] = { 16, 512 };
			int enable_interrupt, transmit_clock_value, tx_clock_source_selection
			double clock;
			transmit_clock_value = (data >> 0) & 0xF;
			tx_clock_source_selection = (data >> 6) & 1;
			enable_interrupt = (data >> 5) & 1;
			clock = (double)(s3c240x_get_pclk(MPLLCON) / div_table[tx_clock_source_selection] / (transmit_clock_value + 1));
#endif
			interrupt_pending_flag = BIT( data, 4);
			if (interrupt_pending_flag == 0)
			{
				int start_stop_condition;
				start_stop_condition = BIT( m_s3c240x_iic_regs[1], 5);
				if (start_stop_condition != 0)
				{
					iic_resume();
				}
			}
		}
		break;
		// IICSTAT
		case 0x04 / 4 :
		{
			int start_stop_condition;
			start_stop_condition = BIT( data, 5);
			if (start_stop_condition != 0)
			{
				iic_start();
			}
			else
			{
				iic_stop();
			}
		}
		break;
	}
}

TIMER_CALLBACK_MEMBER(gp32_state::s3c240x_iic_timer_exp)
{
	int enable_interrupt, mode_selection;
	LOGMASKED(LOG_TIMER, "IIC timer callback\n");
	mode_selection = BITS( m_s3c240x_iic_regs[1], 7, 6);
	switch (mode_selection)
	{
		// master receive mode
		case 2 :
		{
			if (m_s3c240x_iic.data_index == 0)
			{
				uint8_t data_shift = m_s3c240x_iic_regs[3] & 0xFF;
				LOGMASKED(LOG_MISC, "IIC write %02X\n", data_shift);
			}
			else
			{
				uint8_t data_shift = eeprom_read(m_s3c240x_iic.address);
				LOGMASKED(LOG_MISC, "IIC read %02X\n", data_shift);
				m_s3c240x_iic_regs[3] = (m_s3c240x_iic_regs[3] & ~0xFF) | data_shift;
			}
			m_s3c240x_iic.data_index++;
		}
		break;
		// master transmit mode
		case 3 :
		{
			uint8_t data_shift = m_s3c240x_iic_regs[3] & 0xFF;
			LOGMASKED(LOG_MISC, "IIC write %02X\n", data_shift);
			m_s3c240x_iic.data[m_s3c240x_iic.data_index++] = data_shift;
			if (m_s3c240x_iic.data_index == 3)
			{
				m_s3c240x_iic.address = (m_s3c240x_iic.data[1] << 8) | m_s3c240x_iic.data[2];
			}
			if ((m_s3c240x_iic.data_index == 4) && (m_s3c240x_iic.data[0] == 0xA0))
			{
				eeprom_write(m_s3c240x_iic.address, data_shift);
			}
		}
		break;
	}
	enable_interrupt = BIT( m_s3c240x_iic_regs[0], 5);
	if (enable_interrupt)
	{
		s3c240x_request_irq(INT_IIC);
	}
}

// IIS

void gp32_state::s3c240x_iis_start()
{
	static const uint32_t codeclk_table[] = { 256, 384 };
	double freq;
	int prescaler_enable, prescaler_control_a, prescaler_control_b, codeclk;
	LOGMASKED(LOG_STARTSTOP, "IIS start\n");
	prescaler_enable = BIT( m_s3c240x_iis_regs[0], 1);
	prescaler_control_a = BITS( m_s3c240x_iis_regs[2], 9, 5);
	prescaler_control_b = BITS( m_s3c240x_iis_regs[2], 4, 0);
	codeclk = BIT( m_s3c240x_iis_regs[1], 2);
	freq = (double)(s3c240x_get_pclk(MPLLCON) / (prescaler_control_a + 1) / codeclk_table[codeclk]) * 2; // why do I have to multiply by two?
	LOGMASKED(LOG_MISC, "IIS - pclk %d psc_enable %d psc_a %d psc_b %d codeclk %d freq %f\n", s3c240x_get_pclk(MPLLCON), prescaler_enable, prescaler_control_a, prescaler_control_b, codeclk_table[codeclk], freq);
	m_s3c240x_iis_timer->adjust( attotime::from_hz( freq), 0, attotime::from_hz( freq));
}

void gp32_state::s3c240x_iis_stop()
{
	LOGMASKED(LOG_STARTSTOP, "IIS stop\n");
	m_s3c240x_iis_timer->adjust( attotime::never);
}

void gp32_state::s3c240x_iis_recalc()
{
	if (m_s3c240x_iis_regs[0] & 1)
	{
		s3c240x_iis_start();
	}
	else
	{
		s3c240x_iis_stop();
	}
}

READ32_MEMBER(gp32_state::s3c240x_iis_r)
{
	uint32_t data = m_s3c240x_iis_regs[offset];
#if 0
	switch (offset)
	{
		// IISCON
		case 0x00 / 4 :
		{
			data = data & ~1; // for mp3 player
		}
		break;
	}
#endif
	LOGMASKED(LOG_TRACE, "(IIS) %08X -> %08X %s\n", 0x15508000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_iis_w)
{
	uint32_t old_value = m_s3c240x_iis_regs[offset];
	LOGMASKED(LOG_TRACE, "(IIS) %08X <- %08X %s\n", 0x15508000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_iis_regs[offset]);
	switch (offset)
	{
		// IISCON
		case 0x00 / 4 :
		{
			if ((old_value & 1) != (data & 1)) s3c240x_iis_recalc();
		}
		break;
		// IISFIF
		case 0x10 / 4 :
		{
			if (ACCESSING_BITS_16_31)
			{
				m_s3c240x_iis.fifo[m_s3c240x_iis.fifo_index++] = BITS( data, 31, 16);
			}
			if (ACCESSING_BITS_0_15)
			{
				m_s3c240x_iis.fifo[m_s3c240x_iis.fifo_index++] = BITS( data, 15, 0);
			}
			if (m_s3c240x_iis.fifo_index == 2)
			{
				m_s3c240x_iis.fifo_index = 0;
				m_ldac->write(m_s3c240x_iis.fifo[0]);
				m_rdac->write(m_s3c240x_iis.fifo[1]);
			}
		}
		break;
	}
}

TIMER_CALLBACK_MEMBER(gp32_state::s3c240x_iis_timer_exp)
{
	LOGMASKED(LOG_TIMER, "IIS timer callback\n");
	s3c240x_dma_request_iis();
}

// RTC


READ32_MEMBER(gp32_state::s3c240x_rtc_r)
{
	uint32_t data = m_s3c240x_rtc_regs[offset];
	LOGMASKED(LOG_TRACE, "(RTC) %08X -> %08X %s\n", 0x15700040 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_rtc_w)
{
	LOGMASKED(LOG_TRACE, "(RTC) %08X <- %08X %s\n", 0x15700040 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_rtc_regs[offset]);
}

// A/D CONVERTER


READ32_MEMBER(gp32_state::s3c240x_adc_r)
{
	uint32_t data = m_s3c240x_adc_regs[offset];
	LOGMASKED(LOG_TRACE, "(ADC) %08X -> %08X %s\n", 0x15800000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_adc_w)
{
	LOGMASKED(LOG_TRACE, "(ADC) %08X <- %08X %s\n", 0x15800000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_adc_regs[offset]);
}

// SPI


READ32_MEMBER(gp32_state::s3c240x_spi_r)
{
	uint32_t data = m_s3c240x_spi_regs[offset];
	LOGMASKED(LOG_TRACE, "(SPI) %08X -> %08X %s\n", 0x15900000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_spi_w)
{
	LOGMASKED(LOG_TRACE, "(SPI) %08X <- %08X %s\n", 0x15900000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_spi_regs[offset]);
}

// MMC INTERFACE


READ32_MEMBER(gp32_state::s3c240x_mmc_r)
{
	uint32_t data = m_s3c240x_mmc_regs[offset];
	LOGMASKED(LOG_TRACE, "(MMC) %08X -> %08X %s\n", 0x15A00000 + (offset << 2), data, machine().describe_context());
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_mmc_w)
{
	LOGMASKED(LOG_TRACE, "(MMC) %08X <- %08X %s\n", 0x15A00000 + (offset << 2), data, machine().describe_context());
	COMBINE_DATA(&m_s3c240x_mmc_regs[offset]);
}

// ...

void gp32_state::s3c240x_machine_start()
{
	m_s3c240x_pwm_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_pwm_timer_exp),this), (void *)(uintptr_t)0);
	m_s3c240x_pwm_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_pwm_timer_exp),this), (void *)(uintptr_t)1);
	m_s3c240x_pwm_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_pwm_timer_exp),this), (void *)(uintptr_t)2);
	m_s3c240x_pwm_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_pwm_timer_exp),this), (void *)(uintptr_t)3);
	m_s3c240x_pwm_timer[4] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_pwm_timer_exp),this), (void *)(uintptr_t)4);
	m_s3c240x_dma_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_dma_timer_exp),this), (void *)(uintptr_t)0);
	m_s3c240x_dma_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_dma_timer_exp),this), (void *)(uintptr_t)1);
	m_s3c240x_dma_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_dma_timer_exp),this), (void *)(uintptr_t)2);
	m_s3c240x_dma_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_dma_timer_exp),this), (void *)(uintptr_t)3);
	m_s3c240x_iic_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_iic_timer_exp),this), (void *)(uintptr_t)0);
	m_s3c240x_iis_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_iis_timer_exp),this), (void *)(uintptr_t)0);
	m_s3c240x_lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_lcd_timer_exp),this), (void *)(uintptr_t)0);
	m_eeprom_data = std::make_unique<uint8_t[]>(0x2000); // a dump of the EEPROM (S524AB0X91) resulted to be 0x1000
	m_nvram->set_base(m_eeprom_data.get(), 0x2000);
	smc_init();
	i2s_init();
}

void gp32_state::s3c240x_machine_reset()
{
	smc_reset();
	i2s_reset();
	m_s3c240x_iis.fifo_index = 0;
	m_s3c240x_iic.data_index = 0;
}

void gp32_state::gp32_map(address_map &map)
{
	map(0x00000000, 0x0007ffff).rom();
	map(0x0c000000, 0x0c7fffff).ram().share("s3c240x_ram");
	map(0x14000000, 0x1400003b).rw(FUNC(gp32_state::s3c240x_memcon_r), FUNC(gp32_state::s3c240x_memcon_w));
	map(0x14200000, 0x1420005b).rw(FUNC(gp32_state::s3c240x_usb_host_r), FUNC(gp32_state::s3c240x_usb_host_w));
	map(0x14400000, 0x14400017).rw(FUNC(gp32_state::s3c240x_irq_r), FUNC(gp32_state::s3c240x_irq_w));
	map(0x14600000, 0x1460007b).rw(FUNC(gp32_state::s3c240x_dma_r), FUNC(gp32_state::s3c240x_dma_w));
	map(0x14800000, 0x14800017).rw(FUNC(gp32_state::s3c240x_clkpow_r), FUNC(gp32_state::s3c240x_clkpow_w));
	map(0x14a00000, 0x14a003ff).rw(FUNC(gp32_state::s3c240x_lcd_r), FUNC(gp32_state::s3c240x_lcd_w));
	map(0x14a00400, 0x14a007ff).rw(FUNC(gp32_state::s3c240x_lcd_palette_r), FUNC(gp32_state::s3c240x_lcd_palette_w));
	map(0x15000000, 0x1500002b).rw(FUNC(gp32_state::s3c240x_uart_0_r), FUNC(gp32_state::s3c240x_uart_0_w));
	map(0x15004000, 0x1500402b).rw(FUNC(gp32_state::s3c240x_uart_1_r), FUNC(gp32_state::s3c240x_uart_1_w));
	map(0x15100000, 0x15100043).rw(FUNC(gp32_state::s3c240x_pwm_r), FUNC(gp32_state::s3c240x_pwm_w));
	map(0x15200140, 0x152001fb).rw(FUNC(gp32_state::s3c240x_usb_device_r), FUNC(gp32_state::s3c240x_usb_device_w));
	map(0x15300000, 0x1530000b).rw(FUNC(gp32_state::s3c240x_watchdog_r), FUNC(gp32_state::s3c240x_watchdog_w));
	map(0x15400000, 0x1540000f).rw(FUNC(gp32_state::s3c240x_iic_r), FUNC(gp32_state::s3c240x_iic_w));
	map(0x15508000, 0x15508013).rw(FUNC(gp32_state::s3c240x_iis_r), FUNC(gp32_state::s3c240x_iis_w));
	map(0x15600000, 0x1560005b).rw(FUNC(gp32_state::s3c240x_gpio_r), FUNC(gp32_state::s3c240x_gpio_w));
	map(0x15700040, 0x1570008b).rw(FUNC(gp32_state::s3c240x_rtc_r), FUNC(gp32_state::s3c240x_rtc_w));
	map(0x15800000, 0x15800007).rw(FUNC(gp32_state::s3c240x_adc_r), FUNC(gp32_state::s3c240x_adc_w));
	map(0x15900000, 0x15900017).rw(FUNC(gp32_state::s3c240x_spi_r), FUNC(gp32_state::s3c240x_spi_w));
	map(0x15a00000, 0x15a0003f).rw(FUNC(gp32_state::s3c240x_mmc_r), FUNC(gp32_state::s3c240x_mmc_w));
}

static INPUT_PORTS_START( gp32 )
	PORT_START("IN0")
	PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("R") PORT_PLAYER(1)
	PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("L") PORT_PLAYER(1)
	PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
	PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
	PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
	PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
	PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B") PORT_PLAYER(1)
	PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("A") PORT_PLAYER(1)
	PORT_START("IN1")
	PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("SELECT") PORT_PLAYER(1)
	PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("START") PORT_PLAYER(1)
INPUT_PORTS_END

void gp32_state::machine_start()
{
	s3c240x_machine_start();
}

void gp32_state::machine_reset()
{
	s3c240x_machine_reset();
}

void gp32_state::gp32(machine_config &config)
{
	ARM9(config, m_maincpu, 40000000);
	m_maincpu->set_addrmap(AS_PROGRAM, &gp32_state::gp32_map);

	PALETTE(config, m_palette).set_entries(32768);

	SCREEN(config, m_screen, SCREEN_TYPE_LCD);
	m_screen->set_refresh_hz(60);
	m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
	// TODO: bad setup that theoretically should fail a validation check plus console doesn't have vertical screen anyway
	// TODO: retrieve actual defaults from BIOS
	m_screen->set_size(240, 320);
	m_screen->set_visarea(0, 239, 0, 319);
	m_screen->set_screen_update(FUNC(gp32_state::screen_update_gp32));

	SPEAKER(config, "lspeaker").front_left();
	SPEAKER(config, "rspeaker").front_right();
	DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_ldac, 0).add_route(ALL_OUTPUTS, "lspeaker", 1.0); // unknown DAC
	DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_rdac, 0).add_route(ALL_OUTPUTS, "rspeaker", 1.0); // unknown DAC
	voltage_regulator_device &vref(VOLTAGE_REGULATOR(config, "vref"));
	vref.add_route(0, "ldac", 1.0, DAC_VREF_POS_INPUT); vref.add_route(0, "ldac", -1.0, DAC_VREF_NEG_INPUT);
	vref.add_route(0, "rdac", 1.0, DAC_VREF_POS_INPUT); vref.add_route(0, "rdac", -1.0, DAC_VREF_NEG_INPUT);

	NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_1);

	SMARTMEDIA(config, m_smartmedia, 0);

	SOFTWARE_LIST(config, "memc_list").set_original("gp32");
}

ROM_START( gp32 )
	ROM_REGION( 0x80000, "maincpu", 0 )
	ROM_SYSTEM_BIOS( 0, "157e", "Firmware 1.5.7 (English)" )
	ROMX_LOAD( "gp32157e.bin", 0x000000, 0x080000, CRC(b1e35643) SHA1(1566bc2a27980602e9eb501cf8b2d62939bfd1e5), ROM_BIOS(0) )
	ROM_SYSTEM_BIOS( 1, "100k", "Firmware 1.0.0 (Korean)" )
	ROMX_LOAD( "gp32100k.bin", 0x000000, 0x080000, CRC(d9925ac9) SHA1(3604d0d7210ed72eddd3e3e0c108f1102508423c), ROM_BIOS(1) )
	ROM_SYSTEM_BIOS( 2, "156k", "Firmware 1.5.6 (Korean)" )
	ROMX_LOAD( "gp32156k.bin", 0x000000, 0x080000, CRC(667fb1c8) SHA1(d179ab8e96411272b6a1d683e59da752067f9da8), ROM_BIOS(2) )
	ROM_SYSTEM_BIOS( 3, "166m", "Firmware 1.6.6 (European)" )
	ROMX_LOAD( "gp32166m.bin", 0x000000, 0x080000, CRC(4548a840) SHA1(1ad0cab0af28fb45c182e5e8c87ead2aaa4fffe1), ROM_BIOS(3) )
	ROM_SYSTEM_BIOS( 4, "mfv2", "Mr. Spiv Multi Firmware V2" )
	ROMX_LOAD( "gp32mfv2.bin", 0x000000, 0x080000, CRC(7ddaaaeb) SHA1(5a85278f721beb3b00125db5c912d1dc552c5897), ROM_BIOS(4) )

	ROM_REGION( 0x4000, "plds", ROMREGION_ERASEFF )
	ROM_LOAD( "x2c32.jed", 0, 0x3bbb, CRC(eeec10d8) SHA1(34c4b1b865511517a5de1fa352228d95cda387c5) ) // JEDEC format for the time being. X2C32: 32 Macrocell CoolRunner-II CPLD
ROM_END

CONS(2001, gp32, 0, 0, gp32, gp32, gp32_state, empty_init, "Game Park Holdings", "GP32", ROT270 | MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_COLORS )