summaryrefslogblamecommitdiffstatshomepage
path: root/src/mess/drivers/gp32.c
blob: 6d0e00516af9da264f7fe0f2f577f4cad0ed384a (plain) (tree)


















                                                                            
                          
                    


                           
                                                                                                      




















                                                                      


                 




                            
 
                                                             





                                     
                                           

 
                                         
 





                                                                                                                                                                                                        

 
                                       
 





                                                                     

 
                                          
 



                               
                                                                                                 

                                      


                                                                               
                 

                                                                                 

                 
                                     
         
                                            









                                                                                                   
                                            









                                                                                                   
                                         
 

                                                                                 


                               
                                                     

                                        
                                                                                
                                         

                                                                                     
                         


                                                                                                            




                         
                                         
 

                                                                                 


                               
                                                     

                                        
                                                                                
                                         

                                                                                     
                         


                                                                                                            




                         
                                         
 

                                                                                 


                               
                                                      

                                       
                                                                                
                                         

                                                                                     
                         


                                                                                                            




                         
                                         
 

                                                                                 


                               
                                                     

                                       
                                                                                
                                         

                                                                                     
                         


                                                                                                            




                         
                                         
 

                                                                                 


                               
                                                     



                                                                                     

                                                                                     
                         


                                                                                                            




                         

                                                        
                                                         




                                                                                                     
         
                                         
         

                                                                                       
         
                                              
                 




                                                                             
                                                                                                                                               
                 
                                                                                  
         
                                                                                                     



                              
                                                                   

 
                                                                                                             
 
                                                           
                               












                                                                              
                                                                                                           


                      
                                                                                                                                 


                    
                                        
 
                                                         


                                                                                 










                                                                                                                                                                                                       
                                                   
                                                           
                                                                                                                                            
                                                                     
                                           
                                                                                                                                                     


                                                                                           
                                    
 
                                                         



                                                                   

 
                                   
 

                                                      

 
                                     
 
                                      
         
                                    


            
                                   





                                                      
                                                                                                                                 







                                                          
                                                     











                                                    
                                                                                                                                 




                                                 
                                                                                                                                 




                                                                                                  
                                                                                  




                           
                                            

                                      
                                                                





                                                                                              
                                            
 
                                                          
         



                                                          



                 
                                            
 
                                                          
         



                                                          






                                                    
                                                                                                                                    




                                            
                                                                                                                                    





                                                     
                                                                                                    







                       
                                            
 
                                       

                                          
                                             




                                         


                                                                      


            
                                                                     


         
                                                     
 

                                                                
         



                                                                      


            

                                                                   






                                                 
                                                                                                                                 





                                                      
                                                                                                                                 






                                                                                                                                                            
                                                    








































                                                                                                                                                            
                                                                                                                                 


                    
                                             
 



                                                               
                                                            

                                                     



                                                                             



                                            
                                                                                 



                        
                                                                                 

                                    
                                                                                                                                                                                                                                                                                           

                        
                                                                                                           


            
                                                                                   


         
                                            
 

                                                             

 
                                              
 
                                                             
                                                             
         
                                         


            
                                        





                                                      
                                                                                                                                 







                                                          
                                                      


                                                                  
                                                      


                                                                    
                                                      


                                                                      
                                                      


                                                                        
                                                      




                         
                                                        
 

                                                                                                   

                                                                 
         
                                          


            
                                                





         
                                            
 
                                                   




                                                                  
                                             
 
                                                   
                                           
                                                             

                                                                                  
                                                           






                                         
                                                                                                                                     




                            


                                                                                                  

















                                                         
                                                







                                                             
                                                         



                 
                                          
 

                                                               

                                                                                                 
                                       


         
                                          
 
              
                                                               



                               
                                                                 

                                                                                                                 
                                                       




                         
                                           
 
                                      
                                                   

                                                                
                                                         











                                          


                                                                                                                                                                                                                                                                              

                         
                                         


         
                                          
 
                                                        

 
                                            
 
                                               
         
                                       


            
                                      





                                                 
                                                                                                                                 





                                                      
                                                                                                                                 














                                                                                        
                                                                                 













                                                                                        
                                                                                 













                                                                                        
                                                                                 













                                                                                        
                                                                                 




                      
                                                        

                       
                                                                 



             
                            
 








                                                 

 
                           
 

                                                

 
                            
 
                   

                                                           


                    
                                      
 

                                                            
         
                                    
                 

                                                                                       
                 
                                         
                 

                                                                                       


                    

                                                                                    



                 
                             
 
                        
         
                            


            
                                                      
                 
                                                
                 
                                                                                                                          
                 
                                                  









                     
                            
 



                                                 

 
                           
 

                                                

 
                                              
 



                              
                                              
                         

                                                                                




                              
                                              
                         

                                                                                




                              
                                              
                         

                                                                                



























                                                                            
                                                                                      




                               




                                                                     
                                                                                    




                               




                                                                      
                                                                                  
                                  
                                                                                      


                      
                                                                                                                                  





                                              
                                                                                                                                  






                                                                
                                     















                                                                   
                                     








                                                                     
                                     
                                


                                                                        



















                                                    
                                                                                                                                    




                                            
                                                                                                                                    








                                                      
                                                                                                                                   




                                              
                                                                                                                                   

















                                                                                                                                           
                                                                                                                                    




                                            
                                                                                                                                    

















                                                                                                                                           
                                                                                                                                    




                                            
                                                                                                                                    








                                                        
                                                                                                                                   




                                                
                                                                                                                                   








                                                         
                                                                                                                                  




                                              
                                                                                                                                  




                                                       
                                             
 
                   

                                                                          


                    
                                                         
 

                                                                          




      
                                             

















                                                                                    
                                               















                                                                             
                                








                                                 
                               







                                                 
                            
 


                                                              

 
                           
 

                                                      

 
                             
 

                                                              













                                                  
                                                                                                                                 




                                         
                                                                                                                                 













                                                                                             
                                                                                                                                        







                                                                                      
                                                     










                                                             
                                            


                            
                                           





                         
                                                        
 
                                             

                                                            




                                      
                                                          
                         

                                                                                          


                            
                                                                                      

                                                                                                     
                         
                                                   




                                       



                                                                                    
                         
                                                                                                             
                         
                                                                                               
                         
                                                                                



                         
                                                          

                             
                                             




         
                                    
 


                                                                                







                                                                                                                                                                                                                             

 
                                   
 

                                                      

 
                                     
 
                                      
         
                                    


            
                                   
















                                                           
                                                                                                                                 





                                                      
                                                                                                                                 





                                                  
                                                                                














                                                                                                     
                                                             

                                                                                       





                         
                                                        
 
                                                          
                                  







                                                 
                                                                                                                                 




                                         
                                                                                                                                 








                                                  
                                                                                                                                 




                                         
                                                                                                                                 








                                                  
                                                                                                                                 




                                         
                                                                                                                                 








                                                  
                                                                                                                                 




                                         
                                                                                                                                 




                                                  
                                        
 


















                                                                                                                                                          
 



                                     








































                                                                                                   
                                
 
                                

 
                                
 
                                





                                               
                                          





                                                                             
                                                                 



                                                                                







                                                            
                                                    

                                                  




















                                                                                                                                  
/**************************************************************************
 *
 * gp32.c - Game Park GP32
 * Skeleton by R. Belmont
 *
 * CPU: Samsung S3C2400X01 SoC
 * S3C2400X01 consists of:
 *    ARM920T CPU core + MMU
 *    LCD controller
 *    DMA controller
 *    Interrupt controller
 *    USB controller
 *    and more.
 *
 **************************************************************************/

#include "emu.h"
#include "cpu/arm7/arm7.h"
#include "cpu/arm7/arm7core.h"
#include "includes/gp32.h"
#include "rendlay.h"

#define VERBOSE_LEVEL ( 0 )

INLINE void ATTR_PRINTF(3,4) verboselog(running_machine &machine, int n_level, const char *s_fmt, ...)
{
	if (VERBOSE_LEVEL >= n_level)
	{
		va_list v;
		char buf[32768];
		va_start( v, s_fmt);
		vsprintf( buf, s_fmt, v);
		va_end( v);
		logerror( "%s: %s", machine.describe_context( ), buf);
	}
}

#define CLOCK_MULTIPLIER 1

#define MPLLCON  1
#define UPLLCON  2

#define BIT(x,n) (((x)>>(n))&1)
#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 data)
{
	UINT8 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);
	verboselog( machine(), 3, "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 gp32_state::s3c240x_lcd_dma_read( )
{
	UINT8 *vram, data[4];
	int i;
	for (i = 0; i < 2; i++)
	{
		vram = (UINT8 *)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 *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
	int i, j;
	for (i = 0; i < 4; i++)
	{
		UINT32 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 *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
	int i, j;
	for (i = 0; i < 4; i++)
	{
		UINT32 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 *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
	int i, j;
	for (i = 0; i < 4; i++)
	{
		UINT32 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 *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
	int i, j;
	for (i = 0; i < 4; i++)
	{
		UINT32 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 *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
	int i, j;
	for (i = 0; i < 4; i++)
	{
		UINT32 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)
{
	screen_device *screen = machine().first_screen();
	verboselog( machine(), 2, "LCD timer callback\n");
	m_s3c240x_lcd.vpos = screen->vpos();
	m_s3c240x_lcd.hpos = screen->hpos();
	verboselog( machine(), 3, "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();
	}
	verboselog( machine(), 3, "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 : verboselog( machine(), 0, "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( screen->time_until_pos(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos));
}

void gp32_state::video_start()
{
	machine().first_screen()->register_screen_bitmap(m_bitmap);
}

UINT32 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 data = m_s3c240x_lcd_regs[offset];
	switch (offset)
	{
		// LCDCON1
		case 0x00 / 4 :
		{
			// make sure line counter is going
			UINT32 lineval = BITS( m_s3c240x_lcd_regs[1], 23, 14);
			data = (data & ~0xFFFC0000) | ((lineval - machine().first_screen()->vpos()) << 18);
		}
		break;
	}
	verboselog( machine(), 9, "(LCD) %08X -> %08X (PC %08X)\n", 0x14A00000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

void gp32_state::s3c240x_lcd_configure()
{
	screen_device *screen = machine().first_screen();
	UINT32 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);
	verboselog( machine(), 3, "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));
	verboselog( machine(), 3, "LCD - vclk %f\n", vclk);
	framerate = vclk / (((vspw + 1) + (vbpd + 1) + (lineval + 1) + (vfpd + 1)) * ((hspw + 1) + (hbpd + 1) + (hfpd + 1) + (hozval + 1)));
	verboselog( machine(), 3, "LCD - framerate %f\n", framerate);
	visarea.set(0, hozval, 0, lineval);
	verboselog( machine(), 3, "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);
	screen->configure(hozval + 1, lineval + 1, visarea, HZ_TO_ATTOSECONDS( framerate));
}

void gp32_state::s3c240x_lcd_start()
{
	screen_device *screen = machine().first_screen();
	verboselog( machine(), 1, "LCD start\n");
	s3c240x_lcd_configure();
	s3c240x_lcd_dma_init();
	m_s3c240x_lcd_timer->adjust( screen->time_until_pos(0, 0));
}

void gp32_state::s3c240x_lcd_stop()
{
	verboselog( machine(), 1, "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 old_value = m_s3c240x_lcd_regs[offset];
	verboselog( machine(), 9, "(LCD) %08X <- %08X (PC %08X)\n", 0x14A00000 + (offset << 2), data, space.device().safe_pc( ));
	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 data = m_s3c240x_lcd_palette[offset];
	verboselog( machine(), 9, "(LCD) %08X -> %08X (PC %08X)\n", 0x14A00400 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_lcd_palette_w)
{
	verboselog( machine(), 9, "(LCD) %08X <- %08X (PC %08X)\n", 0x14A00400 + (offset << 2), data, space.device().safe_pc( ));
	COMBINE_DATA(&m_s3c240x_lcd_palette[offset]);
	if (mem_mask != 0xffffffff)
	{
		verboselog( machine(), 0, "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 gp32_state::s3c240x_get_fclk(int reg)
{
	UINT32 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)((double)((mdiv + 8) * 12000000) / (double)((pdiv + 2) * (1 << sdiv)));
}

UINT32 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 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 data = m_s3c240x_clkpow_regs[offset];
	verboselog( machine(), 9, "(CLKPOW) %08X -> %08X (PC %08X)\n", 0x14800000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_clkpow_w)
{
	verboselog( machine(), 9, "(CLKPOW) %08X <- %08X (PC %08X)\n", 0x14800000 + (offset << 2), data, space.device().safe_pc( ));
	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 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 int_type)
{
	verboselog( machine(), 5, "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 data = m_s3c240x_irq_regs[offset];
	verboselog( machine(), 9, "(IRQ) %08X -> %08X (PC %08X)\n", 0x14400000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_irq_w)
{
	UINT32 old_value = m_s3c240x_irq_regs[offset];
	verboselog( machine(), 9, "(IRQ) %08X <- %08X (PC %08X)\n", 0x14400000 + (offset << 2), data, space.device().safe_pc( ));
	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 data = m_s3c240x_pwm_regs[offset];
	verboselog( machine(), 9, "(PWM) %08X -> %08X (PC %08X)\n", 0x15100000 + (offset << 2), data, space.device().safe_pc( ));
	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 *regs = &m_s3c240x_pwm_regs[3+timer*3];
	UINT32 prescaler, mux, cnt, cmp, auto_reload;
	double freq, hz;
	verboselog( machine(), 1, "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);
	verboselog( machine(), 5, "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)
{
	verboselog( machine(), 1, "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 old_value = m_s3c240x_pwm_regs[offset];
	verboselog( machine(), 9, "(PWM) %08X <- %08X (PC %08X)\n", 0x15100000 + (offset << 2), data, space.device().safe_pc( ));
	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 };
	verboselog( machine(), 2, "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 *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 *regs = &m_s3c240x_dma_regs[dma<<3];
	UINT32 curr_tc, curr_src, curr_dst;
	address_space &space = m_maincpu->space( AS_PROGRAM);
	int dsz, inc_src, inc_dst, servmode;
	static const UINT32 ch_int[] = { INT_DMA0, INT_DMA1, INT_DMA2, INT_DMA3 };
	verboselog( machine(), 5, "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);
	verboselog( machine(), 5, "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 *regs = &m_s3c240x_dma_regs[2<<3];
	verboselog( machine(), 5, "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;
	verboselog( machine(), 5, "s3c240x_dma_request_pwm\n");
	for (i = 0; i < 4; i++)
	{
		if (i != 1)
		{
			UINT32 *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 addr_src, addr_dst, tc;
	UINT32 *regs = &m_s3c240x_dma_regs[dma<<3];
	UINT32 dsz, tsz, reload;
	int inc_src, inc_dst, _int, servmode, swhwsel, hwsrcsel;
	verboselog( machine(), 1, "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);
	verboselog( machine(), 5, "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);
	verboselog( machine(), 5, "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)
{
	verboselog( machine(), 1, "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 data = m_s3c240x_dma_regs[offset];
	verboselog( machine(), 9, "(DMA) %08X -> %08X (PC %08X)\n", 0x14600000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_dma_w)
{
	UINT32 old_value = m_s3c240x_dma_regs[offset];
	verboselog( machine(), 9, "(DMA) %08X <- %08X (PC %08X)\n", 0x14600000 + (offset << 2), data, space.device().safe_pc( ));
	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;
	verboselog( machine(), 2, "DMA %d timer callback\n", ch);
}

// SMARTMEDIA

void gp32_state::smc_reset()
{
	verboselog( machine(), 5, "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()
{
	verboselog( machine(), 5, "smc_init\n");
	smc_reset();
}

UINT8 gp32_state::smc_read()
{
	UINT8 data;
	data = m_smartmedia->data_r();
	verboselog( machine(), 5, "smc_read %08X\n", data);
	return data;
}

void gp32_state::smc_write(UINT8 data)
{
	verboselog( machine(), 5, "smc_write %08X\n", data);
	if ((m_smc.chip) && (!m_smc.read))
	{
		if (m_smc.cmd_latch)
		{
			verboselog( machine(), 5, "smartmedia_command_w %08X\n", data);
			m_smartmedia->command_w(data);
		}
		else if (m_smc.add_latch)
		{
			verboselog( machine(), 5, "smartmedia_address_w %08X\n", data);
			m_smartmedia->address_w(data);
		}
		else
		{
			verboselog( machine(), 5, "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()
{
	verboselog( machine(), 5, "i2s_reset\n");
	m_i2s.l3d = 0;
	m_i2s.l3m = 0;
	m_i2s.l3c = 0;
}

void gp32_state::i2s_init()
{
	verboselog( machine(), 5, "i2s_init\n");
	i2s_reset();
}

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

// I/O PORT


READ32_MEMBER(gp32_state::s3c240x_gpio_r)
{
	UINT32 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;
	}
	verboselog( machine(), 9, "(GPIO) %08X -> %08X (PC %08X)\n", 0x15600000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_gpio_w)
{
	COMBINE_DATA(&m_s3c240x_gpio[offset]);
	verboselog( machine(), 9, "(GPIO) %08X <- %08X (PC %08X)\n", 0x15600000 + (offset << 2), data, space.device().safe_pc( ));
	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 data = m_s3c240x_memcon_regs[offset];
	verboselog( machine(), 9, "(MEMCON) %08X -> %08X (PC %08X)\n", 0x14000000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_memcon_w)
{
	verboselog( machine(), 9, "(MEMCON) %08X <- %08X (PC %08X)\n", 0x14000000 + (offset << 2), data, space.device().safe_pc( ));
	COMBINE_DATA(&m_s3c240x_memcon_regs[offset]);
}

// USB HOST CONTROLLER


READ32_MEMBER(gp32_state::s3c240x_usb_host_r)
{
	UINT32 data = m_s3c240x_usb_host_regs[offset];
	verboselog( machine(), 9, "(USB H) %08X -> %08X (PC %08X)\n", 0x14200000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_usb_host_w)
{
	verboselog( machine(), 9, "(USB H) %08X <- %08X (PC %08X)\n", 0x14200000 + (offset << 2), data, space.device().safe_pc( ));
	COMBINE_DATA(&m_s3c240x_usb_host_regs[offset]);
}

// UART 0


READ32_MEMBER(gp32_state::s3c240x_uart_0_r)
{
	UINT32 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;
	}
	verboselog( machine(), 9, "(UART 0) %08X -> %08X (PC %08X)\n", 0x15000000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_uart_0_w)
{
	verboselog( machine(), 9, "(UART 0) %08X <- %08X (PC %08X)\n", 0x15000000 + (offset << 2), data, space.device().safe_pc( ));
	COMBINE_DATA(&m_s3c240x_uart_0_regs[offset]);
}

// UART 1


READ32_MEMBER(gp32_state::s3c240x_uart_1_r)
{
	UINT32 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;
	}
	verboselog( machine(), 9, "(UART 1) %08X -> %08X (PC %08X)\n", 0x15004000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_uart_1_w)
{
	verboselog( machine(), 9, "(UART 1) %08X <- %08X (PC %08X)\n", 0x15004000 + (offset << 2), data, space.device().safe_pc( ));
	COMBINE_DATA(&m_s3c240x_uart_1_regs[offset]);
}

// USB DEVICE


READ32_MEMBER(gp32_state::s3c240x_usb_device_r)
{
	UINT32 data = m_s3c240x_usb_device_regs[offset];
	verboselog( machine(), 9, "(USB D) %08X -> %08X (PC %08X)\n", 0x15200140 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_usb_device_w)
{
	verboselog( machine(), 9, "(USB D) %08X <- %08X (PC %08X)\n", 0x15200140 + (offset << 2), data, space.device().safe_pc( ));
	COMBINE_DATA(&m_s3c240x_usb_device_regs[offset]);
}

// WATCHDOG TIMER


READ32_MEMBER(gp32_state::s3c240x_watchdog_r)
{
	UINT32 data = m_s3c240x_watchdog_regs[offset];
	verboselog( machine(), 9, "(WDOG) %08X -> %08X (PC %08X)\n", 0x15300000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_watchdog_w)
{
	verboselog( machine(), 9, "(WDOG) %08X <- %08X (PC %08X)\n", 0x15300000 + (offset << 2), data, space.device().safe_pc( ));
	COMBINE_DATA(&m_s3c240x_watchdog_regs[offset]);
}

// EEPROM

UINT8 gp32_state::eeprom_read(UINT16 address)
{
	UINT8 data;
	data = m_eeprom_data[address];
	verboselog( machine(), 5, "EEPROM %04X -> %02X\n", address, data);
	return data;
}

void gp32_state::eeprom_write(UINT16 address, UINT8 data)
{
	verboselog( machine(), 5, "EEPROM %04X <- %02X\n", address, data);
	m_eeprom_data[address] = data;
}

// IIC

#if 0
UINT8 gp32_state::i2cmem_read_byte( int last)
{
	UINT8 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 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()
{
	verboselog( machine(), 1, "IIC start\n");
	m_s3c240x_iic.data_index = 0;
	m_s3c240x_iic_timer->adjust( attotime::from_msec( 1));
}

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

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

READ32_MEMBER(gp32_state::s3c240x_iic_r)
{
	UINT32 data = m_s3c240x_iic_regs[offset];
	switch (offset)
	{
		// IICSTAT
		case 0x04 / 4 :
		{
			data = data & ~0x0000000F;
		}
		break;
	}
	verboselog( machine(), 9, "(IIC) %08X -> %08X (PC %08X)\n", 0x15400000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_iic_w)
{
	verboselog( machine(), 9, "(IIC) %08X <- %08X (PC %08X)\n", 0x15400000 + (offset << 2), data, space.device().safe_pc( ));
	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;
	verboselog( machine(), 2, "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 data_shift = m_s3c240x_iic_regs[3] & 0xFF;
				verboselog( machine(), 5, "IIC write %02X\n", data_shift);
			}
			else
			{
				UINT8 data_shift = eeprom_read(m_s3c240x_iic.address);
				verboselog( machine(), 5, "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 data_shift = m_s3c240x_iic_regs[3] & 0xFF;
			verboselog( machine(), 5, "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 codeclk_table[] = { 256, 384 };
	double freq;
	int prescaler_enable, prescaler_control_a, prescaler_control_b, codeclk;
	verboselog( machine(), 1, "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?
	verboselog( machine(), 5, "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()
{
	verboselog( machine(), 1, "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 data = m_s3c240x_iis_regs[offset];
#if 0
	switch (offset)
	{
		// IISCON
		case 0x00 / 4 :
		{
			data = data & ~1; // for mp3 player
		}
		break;
	}
#endif
	verboselog( machine(), 9, "(IIS) %08X -> %08X (PC %08X)\n", 0x15508000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_iis_w)
{
	UINT32 old_value = m_s3c240x_iis_regs[offset];
	verboselog( machine(), 9, "(IIS) %08X <- %08X (PC %08X)\n", 0x15508000 + (offset << 2), data, space.device().safe_pc( ));
	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_dac1->write_signed16(m_s3c240x_iis.fifo[0] + 0x8000);
				m_dac2->write_signed16(m_s3c240x_iis.fifo[1] + 0x8000);
			}
		}
		break;
	}
}

TIMER_CALLBACK_MEMBER(gp32_state::s3c240x_iis_timer_exp)
{
	verboselog( machine(), 2, "IIS timer callback\n");
	s3c240x_dma_request_iis();
}

// RTC


READ32_MEMBER(gp32_state::s3c240x_rtc_r)
{
	UINT32 data = m_s3c240x_rtc_regs[offset];
	verboselog( machine(), 9, "(RTC) %08X -> %08X (PC %08X)\n", 0x15700040 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_rtc_w)
{
	verboselog( machine(), 9, "(RTC) %08X <- %08X (PC %08X)\n", 0x15700040 + (offset << 2), data, space.device().safe_pc( ));
	COMBINE_DATA(&m_s3c240x_rtc_regs[offset]);
}

// A/D CONVERTER


READ32_MEMBER(gp32_state::s3c240x_adc_r)
{
	UINT32 data = m_s3c240x_adc_regs[offset];
	verboselog( machine(), 9, "(ADC) %08X -> %08X (PC %08X)\n", 0x15800000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_adc_w)
{
	verboselog( machine(), 9, "(ADC) %08X <- %08X (PC %08X)\n", 0x15800000 + (offset << 2), data, space.device().safe_pc( ));
	COMBINE_DATA(&m_s3c240x_adc_regs[offset]);
}

// SPI


READ32_MEMBER(gp32_state::s3c240x_spi_r)
{
	UINT32 data = m_s3c240x_spi_regs[offset];
	verboselog( machine(), 9, "(SPI) %08X -> %08X (PC %08X)\n", 0x15900000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_spi_w)
{
	verboselog( machine(), 9, "(SPI) %08X <- %08X (PC %08X)\n", 0x15900000 + (offset << 2), data, space.device().safe_pc( ));
	COMBINE_DATA(&m_s3c240x_spi_regs[offset]);
}

// MMC INTERFACE


READ32_MEMBER(gp32_state::s3c240x_mmc_r)
{
	UINT32 data = m_s3c240x_mmc_regs[offset];
	verboselog( machine(), 9, "(MMC) %08X -> %08X (PC %08X)\n", 0x15A00000 + (offset << 2), data, space.device().safe_pc( ));
	return data;
}

WRITE32_MEMBER(gp32_state::s3c240x_mmc_w)
{
	verboselog( machine(), 9, "(MMC) %08X <- %08X (PC %08X)\n", 0x15A00000 + (offset << 2), data, space.device().safe_pc( ));
	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 *)(FPTR)0);
	m_s3c240x_pwm_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_pwm_timer_exp),this), (void *)(FPTR)1);
	m_s3c240x_pwm_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_pwm_timer_exp),this), (void *)(FPTR)2);
	m_s3c240x_pwm_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_pwm_timer_exp),this), (void *)(FPTR)3);
	m_s3c240x_pwm_timer[4] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_pwm_timer_exp),this), (void *)(FPTR)4);
	m_s3c240x_dma_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_dma_timer_exp),this), (void *)(FPTR)0);
	m_s3c240x_dma_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_dma_timer_exp),this), (void *)(FPTR)1);
	m_s3c240x_dma_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_dma_timer_exp),this), (void *)(FPTR)2);
	m_s3c240x_dma_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_dma_timer_exp),this), (void *)(FPTR)3);
	m_s3c240x_iic_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_iic_timer_exp),this), (void *)(FPTR)0);
	m_s3c240x_iis_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_iis_timer_exp),this), (void *)(FPTR)0);
	m_s3c240x_lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gp32_state::s3c240x_lcd_timer_exp),this), (void *)(FPTR)0);
	m_eeprom_data = auto_alloc_array( machine(), UINT8, 0x2000);
	m_nvram->set_base(m_eeprom_data, 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;
}

static ADDRESS_MAP_START( gp32_map, AS_PROGRAM, 32, gp32_state )
	AM_RANGE(0x00000000, 0x0007ffff) AM_ROM
	AM_RANGE(0x0c000000, 0x0c7fffff) AM_RAM AM_SHARE("s3c240x_ram")
	AM_RANGE(0x14000000, 0x1400003b) AM_READWRITE(s3c240x_memcon_r, s3c240x_memcon_w)
	AM_RANGE(0x14200000, 0x1420005b) AM_READWRITE(s3c240x_usb_host_r, s3c240x_usb_host_w)
	AM_RANGE(0x14400000, 0x14400017) AM_READWRITE(s3c240x_irq_r, s3c240x_irq_w)
	AM_RANGE(0x14600000, 0x1460007b) AM_READWRITE(s3c240x_dma_r, s3c240x_dma_w)
	AM_RANGE(0x14800000, 0x14800017) AM_READWRITE(s3c240x_clkpow_r, s3c240x_clkpow_w)
	AM_RANGE(0x14a00000, 0x14a003ff) AM_READWRITE(s3c240x_lcd_r, s3c240x_lcd_w)
	AM_RANGE(0x14a00400, 0x14a007ff) AM_READWRITE(s3c240x_lcd_palette_r, s3c240x_lcd_palette_w)
	AM_RANGE(0x15000000, 0x1500002b) AM_READWRITE(s3c240x_uart_0_r, s3c240x_uart_0_w)
	AM_RANGE(0x15004000, 0x1500402b) AM_READWRITE(s3c240x_uart_1_r, s3c240x_uart_1_w)
	AM_RANGE(0x15100000, 0x15100043) AM_READWRITE(s3c240x_pwm_r, s3c240x_pwm_w)
	AM_RANGE(0x15200140, 0x152001fb) AM_READWRITE(s3c240x_usb_device_r, s3c240x_usb_device_w)
	AM_RANGE(0x15300000, 0x1530000b) AM_READWRITE(s3c240x_watchdog_r, s3c240x_watchdog_w)
	AM_RANGE(0x15400000, 0x1540000f) AM_READWRITE(s3c240x_iic_r, s3c240x_iic_w)
	AM_RANGE(0x15508000, 0x15508013) AM_READWRITE(s3c240x_iis_r, s3c240x_iis_w)
	AM_RANGE(0x15600000, 0x1560005b) AM_READWRITE(s3c240x_gpio_r, s3c240x_gpio_w)
	AM_RANGE(0x15700040, 0x1570008b) AM_READWRITE(s3c240x_rtc_r, s3c240x_rtc_w)
	AM_RANGE(0x15800000, 0x15800007) AM_READWRITE(s3c240x_adc_r, s3c240x_adc_w)
	AM_RANGE(0x15900000, 0x15900017) AM_READWRITE(s3c240x_spi_r, s3c240x_spi_w)
	AM_RANGE(0x15a00000, 0x15a0003f) AM_READWRITE(s3c240x_mmc_r, s3c240x_mmc_w)
ADDRESS_MAP_END

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();
}

static MACHINE_CONFIG_START( gp32, gp32_state )
	MCFG_CPU_ADD("maincpu", ARM9, 40000000)
	MCFG_CPU_PROGRAM_MAP(gp32_map)

	MCFG_PALETTE_ADD("palette", 32768)

	MCFG_SCREEN_ADD("screen", LCD)
	MCFG_SCREEN_REFRESH_RATE(60)
	MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
	MCFG_SCREEN_SIZE(240, 320)
	MCFG_SCREEN_VISIBLE_AREA(0, 239, 0, 319)
	MCFG_SCREEN_UPDATE_DRIVER(gp32_state, screen_update_gp32)

	/* 320x240 is 4:3 but ROT270 causes an aspect ratio of 3:4 by default */
	MCFG_DEFAULT_LAYOUT(layout_lcd_rot)

	MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
	MCFG_SOUND_ADD("dac1", DAC, 0)
	MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0)
	MCFG_SOUND_ADD("dac2", DAC, 0)
	MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0)

	MCFG_NVRAM_ADD_1FILL("nvram")

	MCFG_DEVICE_ADD("smartmedia", SMARTMEDIA, 0)

	MCFG_SOFTWARE_LIST_ADD("memc_list","gp32")
MACHINE_CONFIG_END

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(1) )
	ROM_SYSTEM_BIOS( 1, "100k", "Firmware 1.0.0 (Korean)" )
	ROMX_LOAD( "gp32100k.bin", 0x000000, 0x080000, CRC(d9925ac9) SHA1(3604d0d7210ed72eddd3e3e0c108f1102508423c), ROM_BIOS(2) )
	ROM_SYSTEM_BIOS( 2, "156k", "Firmware 1.5.6 (Korean)" )
	ROMX_LOAD( "gp32156k.bin", 0x000000, 0x080000, CRC(667fb1c8) SHA1(d179ab8e96411272b6a1d683e59da752067f9da8), ROM_BIOS(3) )
	ROM_SYSTEM_BIOS( 3, "166m", "Firmware 1.6.6 (European)" )
	ROMX_LOAD( "gp32166m.bin", 0x000000, 0x080000, CRC(4548a840) SHA1(1ad0cab0af28fb45c182e5e8c87ead2aaa4fffe1), ROM_BIOS(4) )
	ROM_SYSTEM_BIOS( 4, "mfv2", "Mr. Spiv Multi Firmware V2" )
	ROMX_LOAD( "gp32mfv2.bin", 0x000000, 0x080000, CRC(7ddaaaeb) SHA1(5a85278f721beb3b00125db5c912d1dc552c5897), ROM_BIOS(5) )
#if 0
	ROM_SYSTEM_BIOS( 5, "test", "test" )
	ROMX_LOAD( "test.bin", 0x000000, 0x080000, CRC(00000000) SHA1(0000000000000000000000000000000000000000), ROM_BIOS(6) )
#endif
ROM_END

CONS(2001, gp32, 0, 0, gp32, gp32, driver_device, 0, "Game Park Holdings", "GP32", ROT270|GAME_NOT_WORKING|GAME_NO_SOUND)