summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/machine/n64.cpp
blob: d5395995f2d67bf54fd8e36f68e2f0864a86e310 (plain) (tree)
1
2
3
4
5
6
7
8
9

                               

                                                                                  
                
                     
                           
                              
                         
                      
 
                         
                                                                                 
 
                                                                                                         
                                                         
                                                
                                


                             


                                     
 
                                         




                                                         
                                            



                                                         

 
                                                        
 
                     




                                             




                                                                                 
                           




                                            



                                             

                              



                                             

                              



                                             

                              



                                             

                              



                                             

                              



                                             

                              







                                                
                                                                       









                                                          


                                

                                                                                                                          
                                                                                                                          
                                                                                                                                    
                                                                                                                              
                                                                                                                              
                                                   



                                
                                                                                       
 





                                                 
 
                                

                         
                                                    




















                          
                  
 










                                            
                                 

                                              












                            










                                                            



                                 
 

                                            



                                                      



                                            
                          
                       
                                              
 

                     

                                                

                       


                                             
                                                                                                
                                   



                                             
 
                                 



                             
                   
                                                                      
 
                                                 
         



                                     
                             
         
                                                                                              

                               



                                     
                           
         
                                                      

                               



                                     
                           
         
                                                      

                               



                                     
                           
                                                             
         
                                                      

                               



                                     
                           
         






                                   
 













                                                                            
                                                                
 
                         

                       


                                                      
 
                                                         

                                         
 
                                                      

                                           
 
                                                           

                                           

                        
                                                                                                     


                              
                   

 
                                                                           


                       







                                                                              
                         
                                                                  
                         

                                               

                              
                                                     


                                          
                                                       
                 
















































                                                                             



                              
                                                                                                                 


                              
 
                                    
 
                                        
         
                                                                       
         

            
                                                                      







                                                     

 
                                                    


                                   
                           
 
 
                                           
 



















                                                                                  

 
                                                      
 






                                                             

                                                          
                                                             











                                                                                   

 
                                           
 
                                                     

                                               

 
                                       
 
                     

 
                       
 









                               
 
                                                                   
 

                           
                                                                                                


                                  

 
                                                                              
 
                           
         
                                                                                                            

                       



                                          
 

                                       
                                            

                              
         
                                           

         
                              
         
                                               
         
                               
         
                                                 

         
                                                      
         
                                                        

         
                                                         
 
                                                  



                                                
                                            
         

                                                      

                                                                        
 

                                                           
                                                                                          
                         
 

                                               
 
                                                    
                 
         
                                                  
         

                                                      

                                                                        
 

                                                           
                                                                                          
                         
 

                                               
 

                                                    


         
                                              
 
                       
         

                                                                                         
         
 
                       
         
                                                                                          
 
                                                                     
                 
                                                           



                 
                                             


                       
                                                      
                                           
 
                                                       
                                            
 
                                                    
                                                                                          
 
                                                    
                                                        
 
                                                      
                                 
 
                                                      
                                 
 
                                                       
                                            

                                          
                                         


                            
                                                 
                                         
                         
                              
 
                                                   
                                                         
 
                                                 
                                                       
 
                                                     
                                                           
 


                                                       
                                 
 
                                                    
                                                          
 
                                                   
                                                                            
                         
                                               
                                                
                         
                              
 
                                         
                                                                     
 
                        
                                                                                     
                              

         
                 

 
 
                                                                           




                                        
                                                              


                                                   
                                                               


                                                               
                                                            


                                                                   
                                          

                                      
                                                            


                                                                   
                                          

                                      

                                                             

                                                                              
 

                                                                         
                                                                                           
                                                                      


                                                                       
                                                                                            
                                                                     



                                                                       


                                                                              



                                                                            




                                                                           



                                                                                          

                                                                                               

                                                                                      




                                                                                                           



                                                                                                         



                                                                                                 



                                                                                               



                                                                                                 



                                                                                               



                                                                                                 



                                                                                               



                                                                                                 



                                                                                               



                                                                                                 



                                                                                               



                                                                                                 



                                                                                               



                                                                                                 



                                                                                               



                                                                                                 



                                                                                               
                                 
                                                                        

                                      
 
                                                               

                                             
                                                         
                                 


                                      
                                                                                                                         




                                      


                                                        
                                                                                
                                 
                                                                                                  


                                    
                                                                                              



                                      
                                                                                                                         
                                      



                 
 
                
 





                                                                  
 

                                                

 
                                                                


                       
                                                   
                                                         
 
                                                 
                                                       
 
                                                     
                                                           
 
                                                    
                                                          
 
                                                   
                                                                            
                         
                                               
                                                

                              
 
                        
                                                                                                     


                              
                 

 
                                                                           
 
                                                     
 

                       
                                                   
                                                          
                         
                                      
                         

                            

                                                                                         
                         

                              
                                                 

                                                          


                                                                                          
                                                                 
                                                                     




                                                  
                                                                 
                                                                 
                                                                     
                                                  
                                      
                         
 
                                                    
                 
                                                                             


                                                                                      
                                                                                                                 
                                                                                   
                                                                                  
                                                             
                                                                 
                              
                 

                        
                                                                                                                 



                              
                                                        
 
                                           
                                                                    
 

                  
                                             
 

                                                     

                                                            

                                                                            
 
                                                    
                                                                                         
                                                                                                             
 
                                                               

















                                                                                                                                    
 

                                   
                                                                                                 

 
                                                                
 
                         

                       
                                                     

                                         
 

                                                    
                              
 

                                                   
                              

                            
                                      
                              
 
                                                     
                                                                
                              
 

                                                   
                              
 

                                                    
                              
 

                                                    
                              
 

                                                  
                              
 

                                                     
                              
 

                                                     
                              
 

                                                     
                              
 

                                                     
                              
 

                                                     
                              

                        
                                                                                                     

                              
 
                   

 
                                                                           
 
                                                                
 

                       


                                                     

                              

                                                    

                              

                                                         
                         
                                                            
                         
                                        

                              

                                                  
                                                                                    

                              
                                                     
                                                          

                              

                                                   

                              

                                                    
                                                    

                              

                                                    
                                                    

                              

                                                  

                              


                                                     

                              


                                                     

                              

                                                     

                              


                                                     

                              


                                                     

                              





                                                                

                        
                                                                                                                 





                              
                                                                 
 

                                           
                                                                                      



















                                                        

                         

 
                               
 















                                                             
         

 
                                                      
 





                                              
                               
         

 

                                                                                                                                                                    
                          
 
                                         

                                               
 
                                             
          
                                    


                                                                        
 


                                           
                                       
 
                                                                                           
 

                                                             
 
                                
 
                           
                                                                                            
                                 




                                                                 

 
                                                     
 
                        

 
                                 
 
                      
                                           

                                                     
                                         

                         



                                         
                                         
         

 
                                                                
 
                         



                                                 
                                                   
                         
                                                                                                                                          
                         



                                                        

                            


                                        
                 


                                         

                                                    
                              
 
                        
                                                                                                     

                              
 
                   

 
                                                                           
 






                                                       
                                                                                                      



                                                           
                                          






                                                          
                 
                                                   






                                                                                               
                              
                 





                                                     
                                                                                                                 

                              




                       
                                                   
 
                      


                               
 
                               

                                              
 

                                                              
 


                                                    
                                              




                                                             
                                                   


                                                             
         
                                           
                                                             
         

                                                                     
                                                                                       
                                                             


            
                                                                                       
                                                                                              
         
 

                           
                                                                             
                                                                                            


                                               
                                                               
                         
                                                                                                        
                         


                                                   
                 


            
                                                                             
                                                                                           


                                               
                                                               
                         
                                                                                                        
                         


                                                   



                                          


                                                                    
                               





                                              
                                                                
 
                         

                       
                                                       
                                           
                              
 
                                                       
                                           
                              
 
                                                    
                                        
                              
 


                                                      
 


                                                      
 


                                                      
 


                                                      
 


                                                      
 


                                                      
 


                                                      
 


                                                      

                        
                                                                                                     

                              
 
                   

 
                                                                           


                       
                                                       




                                            
                                                       

                                            




                                                                        
                                                                                      





                                                                         
                                                                                      
                         


                              
                                                    
                 
                                                      
                                         

                                       
 
                                                                                                                                                                                       
                                                         


                              
                                                    
                 
                                                       
                                         

                                       
 
                                                                                                                                                                                       
                                                         


                              
                                                    


                                       


                                                                                                 
                                                                  



                              


                                                      
 


                                                      
 


                                                      
 


                                                      
 


                                                      
 


                                                      
 


                                                      
 


                                                      
 
                        
                                                                                                                 




                              
 
                                                                
 

                                         
                                                                           

                                                                             
                                                                            




                                                                                 
                                                     

         
                           
         
                                                                                             
                         
         
                               

 
                                                                           
 
                           
         
                                                                                                         
                       
         
                                       


                   
                                                                 
 

                           
 
                                        
         
                                           






























                                                                
                                             



                                              
                                                                                                                  
 
                                   


                        

                                              
                 


                                        
                                       


                                       


                                                                                                                       

                                                                                        

                                                                 
                                                                            




                                                                        
                                                                           




                                                                        


                                       
                                                             
                                                        
                                                                                                                 
                                                        
 
                                                 


                                       
                                                                                   






                                                 
                                                     
                 
                                             




                                                                                                                                                                         
 






                                                                                                                                         

                                                    
                                                    
                                                    
                                 

                                                                                                                       

                                                                         

                                                                 
                                                                        





                                                                                                                                     

                                                                                

                                                                 
                                                                       
                                                                                                                                     

                                                                                                                                                     
 



                                                                                   
                                                         
                                                                                                 

                                                                                    
                                                                                                                                    
                                                                                          
                                                                                                                                     
 
                                                                                      

                                                         
                                                                                   
                                                         
                                                                                                 

                                                                                    
                                                                                                                                    
                                                                                          
                                                                                                                                     
 
                                                                                      

                                                         
                                                                     
                                                         

                                                                                   
                                                                    
                                                                                   

                                                         
                                                                     
                                                         

                                                                                   
                                                                    
                                                                                   



                                                                                         

                                                                                       


                                                                 





                                 
                                         
                 
                                         
 
                                                               

                                         
                                             
                         
                                                                  



                                                        

                                                                                     
                         
                                                 
                         
                                                                  
                                 
                                                                                              

                                 

                                                                                     
                         
 

                                 
                                          
                 
                                                                        

                                         
                                             
                         
                                                                
                                 
                                                                                              


                                 
                                                                         
 
                                 

                 
                                                   
                 

                                         







                                                                                                                                   
                                                             
 
                                                
                         
                                                                              

                         
                                 

                 
                                                  
                 

                                         







                                                                                                                                   
                                                             
 
                                                  
                         
                                                                                
                         
 


                                 
                                                  
                 





                                        
                                                 



                                        



















                                                                                                             

                                                 


                                 

                        
                                                                                                      






                                 
                              
 
                                         
                                                                                        




                                
                                             
                 
                                                                          
 
                                                


                                        
                                                   




                                             
                                                                                    
                                 

                                                                  
 
                                                                                  




                                                                                         
 
                                                                              



                                                                                    
                                                                                                                                              






                                                                                         
                                                                                      
                                                 
                                                                                            




                                                                               
                                                                                      






                                          
                                                     
         
 
                                             







                                                        

 

                                                   
                      




                                              
                            

                                


                                           
                                        
 
                                         



                                                                                    
                                               
         
                                                                            
 
                                            
                 
                                            



                                                        



                                               
                                               
         
                             
 
                                                                            
 
                                            
                 
                                       





                                                

                 

 
                                             
 
                         

                       
                                                       
                                              
 
                                                    
                                            
         
 
                   

 
                                                                           


                       
                                                       
                                            

                              
                                                            
                                           
                                             
                         
                                                                                    

                                                                  
                                           
                                                 
                                       
                                           
                                                                       

                              
                                                            
                                           
                                             
                         
                                                                                    

                                                                  
                                           
                                                 

                                                                       

                              
                                                    
                                          
                                                              
                                                          







                                                                                         

                                                


                                                                 



















































                                                                                                                    
                                       


































                                                                           
                                                                       



                                  
                                                                                                                                                     
                 
                                                                    
                                                              
                                                                  

































                                                                              
                                                                       





                                   
                        
 
                                                                             




                                                                                      
 











                                                                   
                        
 
                                                                             

                                                                              
                                                          


                                                                                 
                                                       

                                                                                       
                                                                                                    










                                                                             
 
                                             
 




                                         
                            
         
                                                          

         
                                                     
         
                                                           



                          
                         









                                          



                                                                      
                                            




                                                                                                           
                                                                                      

                                               




















                                                      
                                       



                                                                                                 
                              



                                                                

 
                                                                           
 
                                                                                






                                                 
                            
         
                                                                  


                       
                                                     
         
                                                                   














                                                       
                                                                         
                                                                                               


                                                                            

                                                        
                                                                         
                                                                                                


                                                                            

                                                                   
                                                                            

                                                          
                                                                                 

                                                         
                                                                                
                                              
                                                              
                                                                                     
                                              
                                                            
                                                                                   
                                              
                                                                    
                                                                                           
                                              
                                                              
                                                                                     

                                                              
                                                                                     

                                                                  
                                                                                         

                                                              
                                                                                    
                                              
                                                                           
                                                                                     

                                                                  
                                                                                         

                                                                
                                                                                       

                                                                     
                                                                                            


                                                                   
                                                                                          




                                                                                                                                                                   




                                                                 
                                                                                        




                                                                                                                                                        




                                                                      
                                                                                             




                                                                                                                                                            

                                              

                                                                 
                                                                                        

                                              
                                                          
                                 
                                                                                 
                                                                 
                                              



                                                                  
                                                                               


                                         
                                                           

                                                              
                         



                                                         
                         






















                                                                           
                                                             



                                                                                                                   
                                                                                      







                                                                                             
                                                             
                                               
                         
 




                                                








                                                                                                                                                 
         

 
                                                                 
 
                                              









                                                
                                                                                                                                                            

 
                                                                            
 
                                  


                                                                  
                                  


                                                                  
                                 


                                                                  
                                



                                                                  
                                           

 
                                  
 
                                                    

                       
                                                                                                             
 
                              
                              






                                              


                                                                             

                                           
 
                               
 
                                                                    
 
                                        
                                                                        
 



                                                        

                                         
                                                                                                                

 
                               
 
                                                            
 
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/* machine/n64.c - contains N64 hardware emulation shared between MAME and MESS */

#include "emu.h"
#include "debugger.h"
#include "cpu/mips/mips3.h"
#include "cpu/mips/mips3com.h"
#include "includes/n64.h"
#include "video/n64.h"

// device type definition
DEFINE_DEVICE_TYPE(N64PERIPH, n64_periphs, "n64_periphs", "N64 Peripheral Chips")

n64_periphs::n64_periphs(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, N64PERIPH, tag, owner, clock)
	, device_video_interface(mconfig, *this)
	, m_nvram_image(nullptr)
	, dd_present(false)
	, disk_present(false)
	, cart_present(false)
	, m_vr4300(*this, "^maincpu")
	, m_rsp(*this, "^rsp")
	, ai_dac(*this, "^dac%u", 1U)
{
	for (int32_t i = 0; i < 256; i++)
	{
		m_gamma_table[i] = sqrt((float)(i << 6));
		m_gamma_table[i] <<= 1;
	}

	for (int32_t i = 0; i < 0x4000; i++)
	{
		m_gamma_dither_table[i] = sqrt((float)i);
		m_gamma_dither_table[i] <<= 1;
	}
}

TIMER_CALLBACK_MEMBER(n64_periphs::reset_timer_callback)
{
	reset_tick();
}

void n64_periphs::reset_tick()
{
	reset_timer->adjust(attotime::never);
	m_vr4300->reset();
	m_vr4300->set_input_line(INPUT_LINE_IRQ2, CLEAR_LINE);
	m_rsp->reset();
	m_rsp->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
	m_rsp->set_state_int(RSP_SR, m_rsp->state_int(RSP_SR) | RSP_STATUS_HALT);
	reset_held = false;
	cic_status = 0;
	memset(pif_ram, 0, sizeof(pif_ram));
	switch(cic_type)
	{
		case 1:
			pif_ram[0x24] = 0x00;
			pif_ram[0x25] = 0x06;
			pif_ram[0x26] = 0x3f;
			pif_ram[0x27] = 0x3f;
			break;
		case 3:
			pif_ram[0x24] = 0x00;
			pif_ram[0x25] = 0x02;
			pif_ram[0x26] = 0x78;
			pif_ram[0x27] = 0x3f;
			break;
		case 5:
			pif_ram[0x24] = 0x00;
			pif_ram[0x25] = 0x02;
			pif_ram[0x26] = 0x91;
			pif_ram[0x27] = 0x3f;
			break;
		case 6:
			pif_ram[0x24] = 0x00;
			pif_ram[0x25] = 0x02;
			pif_ram[0x26] = 0x85;
			pif_ram[0x27] = 0x3f;
			break;
		case 0xd:
			pif_ram[0x24] = 0x00;
			pif_ram[0x25] = 0x0a;
			pif_ram[0x26] = 0xdd;
			pif_ram[0x27] = 0x3f;
			break;
		default:
			pif_ram[0x24] = 0x00;
			pif_ram[0x25] = 0x02;
			pif_ram[0x26] = 0x3f;
			pif_ram[0x27] = 0x3f;
			break;
	}
}

void n64_periphs::poll_reset_button(bool button)
{
	bool old_held = reset_held;
	reset_held = button;
	if(!old_held && reset_held)
	{
		m_vr4300->set_input_line(INPUT_LINE_IRQ2, ASSERT_LINE);
	}
	else if(old_held && reset_held)
	{
		reset_timer->adjust(attotime::never);
	}
	else if(old_held && !reset_held)
	{
		reset_timer->adjust(attotime::from_hz(1));
	}
}

void n64_periphs::device_start()
{
	ai_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(n64_periphs::ai_timer_callback),this));
	pi_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(n64_periphs::pi_dma_callback),this));
	si_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(n64_periphs::si_dma_callback),this));
	vi_scanline_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(n64_periphs::vi_scanline_callback),this));
	dp_delay_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(n64_periphs::dp_delay_callback),this));
	reset_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(n64_periphs::reset_timer_callback),this));
	m_n64 = machine().driver_data<n64_state>();
}

void n64_periphs::device_reset()
{
	uint32_t *cart = (uint32_t*)machine().root_device().memregion("user2")->base();

	m_mem_map = &m_vr4300->space(AS_PROGRAM);

	m_rdram = m_n64->rdram();
	m_rsp_imem = m_n64->rsp_imem();
	m_rsp_dmem = m_n64->rsp_dmem();
	m_sram = m_n64->sram();

	mi_version = 0x01010101;
	mi_interrupt = 0;
	mi_intr_mask = 0;
	mi_mode = 0x80; // Skip RDRAM initialization

	sp_mem_addr = 0;
	sp_dram_addr = 0;
	sp_dma_length = 0;
	sp_dma_count = 0;
	sp_dma_skip = 0;
	sp_semaphore = 0;

	vi_width = 0;
	vi_origin = 0;
	vi_control = 0;
	vi_burst = 0;
	vi_vsync = 0;
	vi_hsync = 0;
	vi_leap = 0;
	vi_hstart = 0;
	vi_vstart = 0;
	vi_intr = 0;
	vi_vburst = 0;
	vi_xscale = 0;
	vi_yscale = 0;
	field = 0;

	ai_timer->adjust(attotime::never);
	memset(ai_fifo, 0, sizeof(ai_fifo));
	ai_fifo_wpos = 0;
	ai_fifo_rpos = 0;
	ai_fifo_num = 0;
	ai_dram_addr = 0;
	ai_len = 0 ;
	ai_control = 0;
	ai_dacrate = 0;
	ai_bitrate = 0;
	ai_status = 0;
	ai_delayed_carry = false;

	pi_dma_timer->adjust(attotime::never);
	pi_rd_len = 0;
	pi_wr_len = 0;
	pi_status = 0;
	pi_bsd_dom1_lat = 0;
	pi_bsd_dom1_pwd = 0;
	pi_bsd_dom1_pgs = 0;
	pi_bsd_dom1_rls = 0;
	pi_bsd_dom2_lat = 0;
	pi_bsd_dom2_pwd = 0;
	pi_bsd_dom2_pgs = 0;
	pi_bsd_dom2_rls = 0;
	pi_dma_dir = 0;

	memset(dd_buffer, 0, sizeof(dd_buffer));
	memset(dd_sector_data, 0, sizeof(dd_sector_data));
	memset(dd_ram_seq_data, 0, sizeof(dd_ram_seq_data));
	dd_data_reg = 0;
	dd_status_reg = 0;
	dd_track_reg = 0;
	dd_buf_status_reg = 0;
	dd_sector_err_reg = 0;
	dd_seq_status_reg = 0;
	dd_seq_ctrl_reg = 0;
	dd_int = 0;
	dd_bm_reset_held = false;
	dd_write = false;
	dd_zone = 0;
	dd_track_offset = 0;

	memset(ri_regs, 0, sizeof(ri_regs));

	ri_regs[0] = 0xe; // Skip RDRAM initialization
	ri_regs[1] = 0x40; //
	ri_regs[3] = 0x14; //
	ri_regs[4] = 0x63634; //
	memset(pif_ram, 0, sizeof(pif_ram));
	memset(pif_cmd, 0, sizeof(pif_cmd));
	si_dram_addr = 0;
	si_pif_addr = 0;
	si_status_val = 0;
	si_dma_dir = 0;
	si_dma_timer->adjust(attotime::never);

	dp_clock = 0;

	dp_delay_timer->adjust(attotime::never);

	cic_status = 0;

	reset_held = false;
	reset_timer->adjust(attotime::never);

	// bootcode differs between CIC-chips, so we can use its checksum to detect the CIC-chip
	uint64_t boot_checksum = 0;
	for(int i = 0x40; i < 0x1000; i+=4)
	{
		boot_checksum += cart[i/4]+i;
	}

	// CIC-NUS-6102 (default)
	pif_ram[0x24] = 0x00;
	pif_ram[0x25] = 0x00;
	pif_ram[0x26] = 0x3f;
	pif_ram[0x27] = 0x3f;
	cic_type=2;
	m_mem_map->write_dword(0x00000318, 0x800000); /* RDRAM Size */

	if (boot_checksum == 0x00000000001ff230U)
	{
		pif_ram[0x24] = 0x00;
		pif_ram[0x25] = 0x08;
		pif_ram[0x26] = 0xdd;
		pif_ram[0x27] = 0x3f;
		cic_type=0xd;
	}
	else if (boot_checksum == 0x000000cffb830843U || boot_checksum == 0x000000d0027fdf31U)
	{
		// CIC-NUS-6101
		pif_ram[0x24] = 0x00;
		pif_ram[0x25] = 0x04;
		pif_ram[0x26] = 0x3f;
		pif_ram[0x27] = 0x3f;
		cic_type=1;
	}
	else if (boot_checksum == 0x000000d6499e376bU)
	{
		// CIC-NUS-6103
		pif_ram[0x24] = 0x00;
		pif_ram[0x25] = 0x00;
		pif_ram[0x26] = 0x78;
		pif_ram[0x27] = 0x3f;
		cic_type=3;
	}
	else if (boot_checksum == 0x0000011a4a1604b6U)
	{
		// CIC-NUS-6105
		pif_ram[0x24] = 0x00;
		pif_ram[0x25] = 0x00;
		pif_ram[0x26] = 0x91;
		pif_ram[0x27] = 0x3f;
		cic_type=5;
		m_mem_map->write_dword(0x000003f0, 0x800000);
	}
	else if (boot_checksum == 0x000000d6d5de4ba0U)
	{
		// CIC-NUS-6106
		pif_ram[0x24] = 0x00;
		pif_ram[0x25] = 0x00;
		pif_ram[0x26] = 0x85;
		pif_ram[0x27] = 0x3f;
		cic_type=6;
	}

	// Mouse X2/Y2 for delta
	for (int i = 0; i < 4; i++)
	{
		mouse_x2[i] = 0;
		mouse_y2[i] = 0;
	}
}

// Memory Interface (MI)

#define MI_CLR_INIT             0x0080      /* Bit  7: clear init mode */
#define MI_SET_INIT             0x0100      /* Bit  8: set init mode */
#define MI_CLR_EBUS             0x0200      /* Bit  9: clear ebus test */
#define MI_SET_EBUS             0x0400      /* Bit 10: set ebus test mode */
#define MI_CLR_DP_INTR          0x0800      /* Bit 11: clear dp interrupt */
#define MI_CLR_RDRAM            0x1000      /* Bit 12: clear RDRAM reg */
#define MI_SET_RDRAM            0x2000      /* Bit 13: set RDRAM reg mode */
#define MI_MODE_INIT            0x0080      /* Bit  7: init mode */
#define MI_MODE_EBUS            0x0100      /* Bit  8: ebus test mode */
#define MI_MODE_RDRAM           0x0200      /* Bit  9: RDRAM reg mode */

uint32_t n64_periphs::mi_reg_r(offs_t offset, uint32_t mem_mask)
{
	uint32_t ret = 0;
	switch (offset)
	{
		case 0x00/4:            // MI_MODE_REG
			ret = mi_mode;
			break;

		case 0x04/4:            // MI_VERSION_REG
			ret = mi_version;
			break;

		case 0x08/4:            // MI_INTR_REG
			ret = mi_interrupt;
			break;

		case 0x0c/4:            // MI_INTR_MASK_REG
			ret = mi_intr_mask;
			break;

		default:
			logerror("mi_reg_r: %08X, %08X at %08X\n", offset, mem_mask, m_vr4300->pc());
			break;
	}

	return ret;
}

void n64_periphs::mi_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	switch (offset)
	{
		case 0x00/4:        // MI_INIT_MODE_REG
			if (data & MI_CLR_INIT)     mi_mode &= ~MI_MODE_INIT;
			if (data & MI_SET_INIT)     mi_mode |=  MI_MODE_INIT;
			if (data & MI_CLR_EBUS)     mi_mode &= ~MI_MODE_EBUS;
			if (data & MI_SET_EBUS)     mi_mode |=  MI_MODE_EBUS;
			if (data & MI_CLR_RDRAM)    mi_mode &= ~MI_MODE_RDRAM;
			if (data & MI_SET_RDRAM)    mi_mode |=  MI_MODE_RDRAM;
			if (data & MI_CLR_DP_INTR)
			{
				clear_rcp_interrupt(DP_INTERRUPT);
			}
			mi_mode &= ~0x7f;
			mi_mode |= data & 0x7f;
			break;

		case 0x04/4:        // MI_VERSION_REG
			mi_version = data;
			break;

		case 0x0c/4:        // MI_INTR_MASK_REG
		{
			if (data & 0x0001)
			{
				mi_intr_mask &= ~0x1;      // clear SP mask
			}
			if (data & 0x0002)
			{
				mi_intr_mask |= 0x1;           // set SP mask
			}
			if (data & 0x0004)
			{
				mi_intr_mask &= ~0x2;      // clear SI mask
			}
			if (data & 0x0008)
			{
				mi_intr_mask |= 0x2;           // set SI mask
			}
			if (data & 0x0010)
			{
				mi_intr_mask &= ~0x4;      // clear AI mask
			}
			if (data & 0x0020)
			{
				mi_intr_mask |= 0x4;           // set AI mask
			}
			if (data & 0x0040)
			{
				mi_intr_mask &= ~0x8;      // clear VI mask
			}
			if (data & 0x0080)
			{
				mi_intr_mask |= 0x8;           // set VI mask
			}
			if (data & 0x0100)
			{
				mi_intr_mask &= ~0x10;     // clear PI mask
			}
			if (data & 0x0200)
			{
				mi_intr_mask |= 0x10;      // set PI mask
			}
			if (data & 0x0400)
			{
				mi_intr_mask &= ~0x20;     // clear DP mask
			}
			if (data & 0x0800)
			{
				mi_intr_mask |= 0x20;      // set DP mask
			}
			check_interrupts();
			break;
		}

		default:
			logerror("mi_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, m_vr4300->pc());
			break;
	}
}

void n64_periphs::check_interrupts()
{
	if (mi_intr_mask & mi_interrupt)
	{
		m_vr4300->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
	}
	else
	{
		m_vr4300->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
	}
}

void n64_periphs::signal_rcp_interrupt(int interrupt)
{
	mi_interrupt |= interrupt;

	check_interrupts();
}

void n64_periphs::clear_rcp_interrupt(int interrupt)
{
	mi_interrupt &= ~interrupt;

	check_interrupts();
}

uint32_t n64_periphs::is64_r(offs_t offset)
{
	switch(offset)
	{
		case 0x0000/4:
			return 0x49533634;

		case 0x0004/4:
		case 0x0008/4:
		case 0x000c/4:
		case 0x0010/4:
		case 0x0014/4:
		case 0x0018/4:
		case 0x001c/4:
			return 0;

		default:
			return ( is64_buffer[(offset << 2) + 0] << 24 ) |
					( is64_buffer[(offset << 2) + 1] << 16 ) |
					( is64_buffer[(offset << 2) + 2] <<  8 ) |
					( is64_buffer[(offset << 2) + 3] <<  0 );
	}
}

void n64_periphs::is64_w(offs_t offset, uint32_t data)
{
	int i = 0;

	switch(offset)
	{
		case 0x0014/4:
			for(i = 0x20; i < (0x20 + data); i++)
			{
				if(is64_buffer[i] == 0x0a)
				{
					printf( "%c", 0x0d );
				}
				is64_buffer[i] = 0;
			}
			break;

		default:
			is64_buffer[(offset << 2) + 0] = (data >> 24) & 0x000000ff;
			is64_buffer[(offset << 2) + 1] = (data >> 16) & 0x000000ff;
			is64_buffer[(offset << 2) + 2] = (data >>  8) & 0x000000ff;
			is64_buffer[(offset << 2) + 3] = (data >>  0) & 0x000000ff;
			break;
	}
}

uint32_t n64_periphs::open_r(offs_t offset)
{
	uint32_t retval = (offset << 2) & 0x0000ffff;
	retval = ((retval + 2) << 16) | retval;
	return retval;
}

void n64_periphs::open_w(uint32_t data)
{
	// Do nothing
}

// RDRAM Interface (RI)

#define RDRAM_CONFIG        (0)
#define RDRAM_DEVICE_ID     (1)
#define RDRAM_DELAY         (2)
#define RDRAM_MODE          (3)
#define RDRAM_REF_INTERVAL  (4)
#define RDRAM_REF_ROW       (5)
#define RDRAM_RAS_INTERVAL  (6)
#define RDRAM_MIN_INTERVAL  (7)
#define RDRAM_ADDR_SELECT   (8)
#define RDRAM_DEVICE_MANUF  (9)

uint32_t n64_periphs::rdram_reg_r(offs_t offset, uint32_t mem_mask)
{
	if(offset > 0x24/4)
	{
		logerror("rdram_reg_r: %08X, %08X at %08X\n", offset, mem_mask, m_vr4300->pc());
		return 0;
	}
	return rdram_regs[offset];
}

void n64_periphs::rdram_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	if(offset > 0x24/4)
	{
		logerror("rdram_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, m_vr4300->pc());
		return;
	}
	COMBINE_DATA(&rdram_regs[offset]);
}

// RSP Interface

void n64_periphs::sp_dma(int direction)
{
	uint32_t length = sp_dma_length + 1;

	if ((length & 7) != 0)
	{
		length = (length + 7) & ~7;
	}

	if (sp_mem_addr & 0x7)
	{
		sp_mem_addr = sp_mem_addr & ~7;
	}
	if (sp_dram_addr & 0x7)
	{
		sp_dram_addr = sp_dram_addr & ~7;
	}

	if ((sp_mem_addr & 0xfff) + (length) > 0x1000)
	{
		length = 0x1000 - (sp_mem_addr & 0xfff);
	}

	uint32_t *sp_mem[2] = { m_rsp_dmem, m_rsp_imem };

	int sp_mem_page = (sp_mem_addr >> 12) & 1;

	if(sp_mem_page == 1)
		m_rsp->rspdrc_flush_drc_cache();

	if(direction == 0)// RDRAM -> I/DMEM
	{
		for(int c = 0; c <= sp_dma_count; c++)
		{
			uint32_t src = (sp_dram_addr & 0x007fffff) >> 2;
			uint32_t dst = (sp_mem_addr & 0xfff) >> 2;

			for(int i = 0; i < length / 4; i++)
			{
				sp_mem[sp_mem_page][(dst + i) & 0x3ff] = m_rdram[src + i];
			}

			sp_mem_addr += length;
			sp_dram_addr += length;

			sp_dram_addr += sp_dma_skip;
		}
	}
	else                    // I/DMEM -> RDRAM
	{
		for(int c = 0; c <= sp_dma_count; c++)
		{
			uint32_t src = (sp_mem_addr & 0xfff) >> 2;
			uint32_t dst = (sp_dram_addr & 0x007fffff) >> 2;

			for(int i = 0; i < length / 4; i++)
			{
				m_rdram[dst + i] = sp_mem[sp_mem_page][(src + i) & 0x3ff];
			}

			sp_mem_addr += length;
			sp_dram_addr += length;

			sp_dram_addr += sp_dma_skip;
		}
	}
}

void n64_periphs::sp_set_status(uint32_t data)
{
	if (data & 0x1)
	{
		m_rsp->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
		m_rsp->set_state_int(RSP_SR, m_rsp->state_int(RSP_SR) | RSP_STATUS_HALT);
	}

	if (data & 0x2)
	{
		m_rsp->set_state_int(RSP_SR, m_rsp->state_int(RSP_SR) | RSP_STATUS_BROKE);

		if (m_rsp->state_int(RSP_SR) & RSP_STATUS_INTR_BREAK)
		{
			signal_rcp_interrupt(SP_INTERRUPT);
		}
	}
}

uint32_t n64_periphs::sp_reg_r(offs_t offset)
{
	switch (offset)
	{
		case 0x00/4:        // SP_MEM_ADDR_REG
			return sp_mem_addr;

		case 0x04/4:        // SP_DRAM_ADDR_REG
			return sp_dram_addr;

		case 0x08/4:        // SP_RD_LEN_REG
			return (sp_dma_skip << 20) | (sp_dma_count << 12) | sp_dma_length;

		case 0x10/4:        // SP_STATUS_REG
			return m_rsp->state_int(RSP_SR);

		case 0x14/4:        // SP_DMA_FULL_REG
			return 0;

		case 0x18/4:        // SP_DMA_BUSY_REG
			return 0;

		case 0x1c/4:        // SP_SEMAPHORE_REG
			//m_vr4300->yield();
			if( sp_semaphore )
			{
				return 1;
			}
			else
			{
				sp_semaphore = 1;
				return 0;
			}
			break;

		case 0x20/4:        // DP_CMD_START
			return m_n64->rdp()->get_start();

		case 0x24/4:        // DP_CMD_END
			return m_n64->rdp()->get_end();

		case 0x28/4:        // DP_CMD_CURRENT
			return m_n64->rdp()->get_current();

		case 0x34/4:        // DP_CMD_BUSY
		case 0x38/4:        // DP_CMD_PIPE_BUSY
		case 0x3c/4:        // DP_CMD_TMEM_BUSY
			return 0;

		case 0x2c/4:        // DP_CMD_STATUS
			return m_n64->rdp()->get_status();

		case 0x30/4:        // DP_CMD_CLOCK
			if(!(m_n64->rdp()->get_status() & DP_STATUS_FREEZE))
			{
				dp_clock += 13;
				return dp_clock;
			}
			break;

		case 0x40000/4:     // PC
			return m_rsp->state_int(RSP_PC) & 0x00000fff;

		default:
			logerror("sp_reg_r: %08X at %08X\n", offset, m_vr4300->pc());
			break;
	}

	return 0;
}


void n64_periphs::sp_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	if ((offset & 0x10000) == 0)
	{
		switch (offset & 0xffff)
		{
			case 0x00/4:        // SP_MEM_ADDR_REG
				sp_mem_addr = data;
				break;

			case 0x04/4:        // SP_DRAM_ADDR_REG
				sp_dram_addr = data & 0xffffff;
				break;

			case 0x08/4:        // SP_RD_LEN_REG
				sp_dma_length = data & 0xfff;
				sp_dma_count = (data >> 12) & 0xff;
				sp_dma_skip = (data >> 20) & 0xfff;
				sp_dma(0);
				break;

			case 0x0c/4:        // SP_WR_LEN_REG
				sp_dma_length = data & 0xfff;
				sp_dma_count = (data >> 12) & 0xff;
				sp_dma_skip = (data >> 20) & 0xfff;
				sp_dma(1);
				break;

			case 0x10/4:        // RSP_STATUS_REG
			{
				uint32_t oldstatus = m_rsp->state_int(RSP_SR);
				uint32_t newstatus = oldstatus;

				if (data & 0x00000001)      // clear halt
				{
					m_rsp->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
					newstatus &= ~RSP_STATUS_HALT;
				}
				if (data & 0x00000002)      // set halt
				{
					m_rsp->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
					newstatus |= RSP_STATUS_HALT;
				}
				if (data & 0x00000004)
				{
					newstatus &= ~RSP_STATUS_BROKE;
				}
				if (data & 0x00000008)      // clear interrupt
				{
					clear_rcp_interrupt(SP_INTERRUPT);
				}
				if (data & 0x00000010)      // set interrupt
				{
					signal_rcp_interrupt(SP_INTERRUPT);
				}
				if (data & 0x00000020)
				{
					newstatus &= ~RSP_STATUS_SSTEP;
				}
				if (data & 0x00000040)
				{
					newstatus |= RSP_STATUS_SSTEP;  // set single step
					if(!(oldstatus & (RSP_STATUS_BROKE | RSP_STATUS_HALT)))
					{
						m_rsp->set_state_int(RSP_STEPCNT, 1 );
						m_rsp->yield();
					}
				}
				if (data & 0x00000080)
				{
					newstatus &= ~RSP_STATUS_INTR_BREAK;    // clear interrupt on break
				}
				if (data & 0x00000100)
				{
					newstatus |= RSP_STATUS_INTR_BREAK;     // set interrupt on break
				}
				if (data & 0x00000200)
				{
					newstatus &= ~RSP_STATUS_SIGNAL0;       // clear signal 0
				}
				if (data & 0x00000400)
				{
					newstatus |= RSP_STATUS_SIGNAL0;        // set signal 0
				}
				if (data & 0x00000800)
				{
					newstatus &= ~RSP_STATUS_SIGNAL1;       // clear signal 1
				}
				if (data & 0x00001000)
				{
					newstatus |= RSP_STATUS_SIGNAL1;        // set signal 1
				}
				if (data & 0x00002000)
				{
					newstatus &= ~RSP_STATUS_SIGNAL2 ;      // clear signal 2
				}
				if (data & 0x00004000)
				{
					newstatus |= RSP_STATUS_SIGNAL2;        // set signal 2
				}
				if (data & 0x00008000)
				{
					newstatus &= ~RSP_STATUS_SIGNAL3;       // clear signal 3
				}
				if (data & 0x00010000)
				{
					newstatus |= RSP_STATUS_SIGNAL3;        // set signal 3
				}
				if (data & 0x00020000)
				{
					newstatus &= ~RSP_STATUS_SIGNAL4;       // clear signal 4
				}
				if (data & 0x00040000)
				{
					newstatus |= RSP_STATUS_SIGNAL4;        // set signal 4
				}
				if (data & 0x00080000)
				{
					newstatus &= ~RSP_STATUS_SIGNAL5;       // clear signal 5
				}
				if (data & 0x00100000)
				{
					newstatus |= RSP_STATUS_SIGNAL5;        // set signal 5
				}
				if (data & 0x00200000)
				{
					newstatus &= ~RSP_STATUS_SIGNAL6;       // clear signal 6
				}
				if (data & 0x00400000)
				{
					newstatus |= RSP_STATUS_SIGNAL6;        // set signal 6
				}
				if (data & 0x00800000)
				{
					newstatus &= ~RSP_STATUS_SIGNAL7;       // clear signal 7
				}
				if (data & 0x01000000)
				{
					newstatus |= RSP_STATUS_SIGNAL7;        // set signal 7
				}
				m_rsp->set_state_int(RSP_SR, newstatus);
				break;
			}

			case 0x1c/4:        // SP_SEMAPHORE_REG
				if(data == 0)
				{
					sp_semaphore = 0;
				}
				break;

			default:
				logerror("sp_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, m_vr4300->pc());
				break;
		}
	}
	else
	{
		switch (offset & 0xffff)
		{
			case 0x00/4:        // SP_PC_REG
				if( m_rsp->state_int(RSP_NEXTPC) != 0xffffffff )
				{
					m_rsp->set_state_int(RSP_NEXTPC, 0x1000 | (data & 0xfff));
				}
				else
				{
					m_rsp->set_state_int(RSP_PC, 0x1000 | (data & 0xfff));
				}
				break;

			default:
				logerror("sp_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, m_vr4300->pc());
				break;
		}
	}
}


// RDP Interface

void n64_periphs::dp_full_sync()
{
	dp_delay_timer->adjust(attotime::from_hz(62500000 / 100));
}

TIMER_CALLBACK_MEMBER(n64_periphs::dp_delay_callback)
{
	dp_delay_timer->adjust(attotime::never);
	signal_rcp_interrupt(DP_INTERRUPT);
}

uint32_t n64_periphs::dp_reg_r(offs_t offset, uint32_t mem_mask)
{
	switch (offset)
	{
		case 0x00/4:        // DP_START_REG
			return m_n64->rdp()->get_start();

		case 0x04/4:        // DP_END_REG
			return m_n64->rdp()->get_end();

		case 0x08/4:        // DP_CURRENT_REG
			return m_n64->rdp()->get_current();

		case 0x0c/4:        // DP_STATUS_REG
			return m_n64->rdp()->get_status();

		case 0x10/4:        // DP_CLOCK_REG
			if(!(m_n64->rdp()->get_status() & DP_STATUS_FREEZE))
			{
				dp_clock += 13;
				return dp_clock;
			}
			break;

		default:
			logerror("dp_reg_r: %08X, %08X at %08X\n", offset, mem_mask, m_vr4300->pc());
			break;
	}

	return 0;
}

void n64_periphs::dp_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	uint32_t status = m_n64->rdp()->get_status();

	switch (offset)
	{
		case 0x00/4:        // DP_START_REG
			if(status & DP_STATUS_START_VALID)
			{
				break;
			}
			else
			{
				m_n64->rdp()->set_status(status | DP_STATUS_START_VALID);
				m_n64->rdp()->set_start(data & ~7);
			}
			break;

		case 0x04/4:        // DP_END_REG
			if(status & DP_STATUS_START_VALID)
			{
				m_n64->rdp()->set_status(status & ~DP_STATUS_START_VALID);
				m_n64->rdp()->set_current(m_n64->rdp()->get_start());
				m_n64->rdp()->set_end(data & ~7);
				g_profiler.start(PROFILER_USER1);
				m_n64->rdp()->process_command_list();
				g_profiler.stop();
				break;
			}
			else
			{
				m_n64->rdp()->set_end(data & ~7);
				g_profiler.start(PROFILER_USER1);
				m_n64->rdp()->process_command_list();
				g_profiler.stop();
				break;
			}

		case 0x0c/4:        // DP_STATUS_REG
		{
			uint32_t current_status = m_n64->rdp()->get_status();
			if (data & 0x00000001)  current_status &= ~DP_STATUS_XBUS_DMA;
			if (data & 0x00000002)  current_status |= DP_STATUS_XBUS_DMA;
			if (data & 0x00000004)  current_status &= ~DP_STATUS_FREEZE;
			//if (data & 0x00000008)  current_status |= DP_STATUS_FREEZE; // Temp: Do nothing for now
			if (data & 0x00000010)  current_status &= ~DP_STATUS_FLUSH;
			if (data & 0x00000020)  current_status |= DP_STATUS_FLUSH;
			if (data & 0x00000200)  dp_clock = 0;
			m_n64->rdp()->set_status(current_status);
			break;
		}

		default:
			logerror("dp_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, m_vr4300->pc());
			break;
	}
}

TIMER_CALLBACK_MEMBER(n64_periphs::vi_scanline_callback)
{
	signal_rcp_interrupt(VI_INTERRUPT);
	vi_scanline_timer->adjust(screen().time_until_pos(vi_intr));
}

// Video Interface
void n64_periphs::vi_recalculate_resolution()
{
	int x_start = (vi_hstart & 0x03ff0000) >> 16;
	int x_end = vi_hstart & 0x000003ff;
	int y_start = ((vi_vstart & 0x03ff0000) >> 16) >> 1;
	int y_end = (vi_vstart & 0x000003ff) >> 1;
	int width = ((vi_xscale & 0x00000fff) * (x_end - x_start)) / 0x400;
	int height = ((vi_yscale & 0x00000fff) * (y_end - y_start)) / 0x400;

	rectangle visarea = screen().visible_area();
	// DACRATE is the quarter pixel clock and period will be for a field, not a frame
	attoseconds_t period = (vi_hsync & 0xfff) * (vi_vsync & 0xfff) * HZ_TO_ATTOSECONDS(DACRATE_NTSC) / 2;

	if (width == 0 || height == 0 || (vi_control & 3) == 0)
	{
		vi_blank = 1;
		/*
		FIXME: MAME doesn't handle well a h/w res of zero (otherwise it hardlocks the emu, seen especially in Aleck 64 games
		that sets the res after a longer delay than n64), guess that this just disables drawing?
		*/
		return;
	}
	else
	{
		vi_blank = 0;
	}

	if (width > 640)
		width = 640;

	if (height > 480)
		height = 480;

	visarea.max_x = width - 1;
	visarea.max_y = height - 1;
	screen().configure((vi_hsync & 0x00000fff)>>2, (vi_vsync & 0x00000fff), visarea, period);
}

uint32_t n64_periphs::vi_reg_r(offs_t offset, uint32_t mem_mask)
{
	uint32_t ret = 0;
	switch (offset)
	{
		case 0x00/4:        // VI_CONTROL_REG
			ret = vi_control;
			break;

		case 0x04/4:        // VI_ORIGIN_REG
			ret = vi_origin;
			break;

		case 0x08/4:        // VI_WIDTH_REG
			ret = vi_width;
			break;

		case 0x0c/4:
			ret = vi_intr;
			break;

		case 0x10/4:        // VI_CURRENT_REG
			ret = (screen().vpos() & 0x3FE) + field;
			break;

		case 0x14/4:        // VI_BURST_REG
			ret = vi_burst;
			break;

		case 0x18/4:        // VI_V_SYNC_REG
			ret = vi_vsync;
			break;

		case 0x1c/4:        // VI_H_SYNC_REG
			ret = vi_hsync;
			break;

		case 0x20/4:        // VI_LEAP_REG
			ret = vi_leap;
			break;

		case 0x24/4:        // VI_H_START_REG
			ret = vi_hstart;
			break;

		case 0x28/4:        // VI_V_START_REG
			ret = vi_vstart;
			break;

		case 0x2c/4:        // VI_V_BURST_REG
			ret = vi_vburst;
			break;

		case 0x30/4:        // VI_X_SCALE_REG
			ret = vi_xscale;
			break;

		case 0x34/4:        // VI_Y_SCALE_REG
			ret = vi_yscale;
			break;

		default:
			logerror("vi_reg_r: %08X, %08X at %08X\n", offset, mem_mask, m_vr4300->pc());
			break;
	}

	return ret;
}

void n64_periphs::vi_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	//n64_state *state = machine().driver_data<n64_state>();

	switch (offset)
	{
		case 0x00/4:        // VI_CONTROL_REG
			vi_control = data;
			vi_recalculate_resolution();
			break;

		case 0x04/4:        // VI_ORIGIN_REG
			vi_origin = data & 0xffffff;
			break;

		case 0x08/4:        // VI_WIDTH_REG
			if (vi_width != data && data > 0)
			{
				vi_recalculate_resolution();
			}
			vi_width = data;
			break;

		case 0x0c/4:        // VI_INTR_REG
			vi_intr = data;
			vi_scanline_timer->adjust(screen().time_until_pos(vi_intr));
			break;

		case 0x10/4:        // VI_CURRENT_REG
			clear_rcp_interrupt(VI_INTERRUPT);
			break;

		case 0x14/4:        // VI_BURST_REG
			vi_burst = data;
			break;

		case 0x18/4:        // VI_V_SYNC_REG
			vi_vsync = data;
			vi_recalculate_resolution();
			break;

		case 0x1c/4:        // VI_H_SYNC_REG
			vi_hsync = data;
			vi_recalculate_resolution();
			break;

		case 0x20/4:        // VI_LEAP_REG
			vi_leap = data;
			break;

		case 0x24/4:        // VI_H_START_REG
			vi_hstart = data;
			vi_recalculate_resolution();
			break;

		case 0x28/4:        // VI_V_START_REG
			vi_vstart = data;
			vi_recalculate_resolution();
			break;

		case 0x2c/4:        // VI_V_BURST_REG
			vi_vburst = data;
			break;

		case 0x30/4:        // VI_X_SCALE_REG
			vi_xscale = data;
			vi_recalculate_resolution();
			break;

		case 0x34/4:        // VI_Y_SCALE_REG
			vi_yscale = data;
			vi_recalculate_resolution();
			break;

		/*
		Uncomment this for convenient homebrew debugging
		case 0x44/4:        // TEMP DEBUG
		    printf( "E Ping: %08x\n", data );
		    break;
		*/

		default:
			logerror("vi_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, m_vr4300->pc());
			break;
	}
}


// Audio Interface
void n64_periphs::ai_fifo_push(uint32_t address, uint32_t length)
{
	if (ai_fifo_num == AUDIO_DMA_DEPTH)
	{
		osd_printf_debug("ai_fifo_push: tried to push to full DMA FIFO!!!\n");
	}

	ai_fifo[ai_fifo_wpos].address = address;
	ai_fifo[ai_fifo_wpos].length = length;

	ai_fifo_wpos++;
	ai_fifo_num++;

	if (ai_fifo_wpos >= AUDIO_DMA_DEPTH)
	{
		ai_fifo_wpos = 0;
	}

	if (ai_fifo_num >= AUDIO_DMA_DEPTH)
	{
		ai_status |= 0x80000001;    // FIFO full
	}

	if (! (ai_status & 0x40000000))
	{
		ai_dma();
	}
}

void n64_periphs::ai_fifo_pop()
{
	ai_fifo_rpos++;
	ai_fifo_num--;

	if (ai_fifo_num < 0)
	{
		fatalerror("ai_fifo_pop: FIFO underflow!\n");
	}

	if (ai_fifo_rpos >= AUDIO_DMA_DEPTH)
	{
		ai_fifo_rpos = 0;
	}

	if (ai_fifo_num < AUDIO_DMA_DEPTH)
	{
		ai_status &= ~0x80000001;   // FIFO not full
	}
}

n64_periphs::AUDIO_DMA *n64_periphs::ai_fifo_get_top()
{
	if (ai_fifo_num > 0)
	{
		return &ai_fifo[ai_fifo_rpos];
	}
	else
	{
		return nullptr;
	}
}

#define N64_ATTOTIME_NORMALIZE(a)   do { while ((a).attoseconds >= ATTOSECONDS_PER_SECOND) { (a).seconds++; (a).attoseconds -= ATTOSECONDS_PER_SECOND; } } while (0)

void n64_periphs::ai_dma()
{
	int16_t *ram = (int16_t*)m_rdram;
	AUDIO_DMA *current = ai_fifo_get_top();
	attotime period;

	//static FILE * audio_dump = nullptr;
	//
	//if (audio_dump == nullptr)
	//    audio_dump = fopen("audio_dump.raw","wb");
	//
	//fwrite(&ram[current->address/2],current->length,1,audio_dump);

	if (ai_delayed_carry)
		current->address += 0x2000;

	ram = &ram[current->address/2];

	//osd_printf_debug("DACDMA: %x for %x bytes\n", current->address, current->length);

	ai_dac[0]->transfer(0, 1, 2, current->length/4, ram);
	ai_dac[1]->transfer(1, 1, 2, current->length/4, ram);

	ai_status |= 0x40000000;

	// adjust the timer
	period = attotime::from_hz(DACRATE_NTSC) * (ai_dacrate + 1) * (current->length / 4);
	ai_timer->adjust(period);

	if (((current->address + current->length) & 0x1FFF) == 0)
		ai_delayed_carry = true;
	else
		ai_delayed_carry = false;
}

TIMER_CALLBACK_MEMBER(n64_periphs::ai_timer_callback)
{
	ai_timer_tick();
}

void n64_periphs::ai_timer_tick()
{
	ai_fifo_pop();
	signal_rcp_interrupt(AI_INTERRUPT);

	// keep playing if there's another DMA queued
	if (ai_fifo_get_top() != nullptr)
	{
		ai_dma();
	}
	else
	{
		ai_status &= ~0x40000000;
		ai_delayed_carry = false;
	}
}

uint32_t n64_periphs::ai_reg_r(offs_t offset, uint32_t mem_mask)
{
	uint32_t ret = 0;
	switch (offset)
	{
		case 0x04/4:        // AI_LEN_REG
		{
			if (ai_status & 0x40000000)
			{
				ret = 4 * (uint32_t)(ai_timer->remaining().as_double() * (double)DACRATE_NTSC / (double)(ai_dacrate + 1));
			}
			else if (ai_status & 0x80000001)
			{
				ret = ai_len;
			}
			else
			{
				ret = 0;
			}
			break;
		}
		case 0x08/4:
			ret = ai_control;
			break;
		case 0x0c/4:        // AI_STATUS_REG
			ret = ai_status;
			break;

		default:
			logerror("ai_reg_r: %08X, %08X at %08X\n", offset, mem_mask, m_vr4300->pc());
			break;
	}

	return ret;
}

void n64_periphs::ai_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	switch (offset)
	{
		case 0x00/4:        // AI_DRAM_ADDR_REG
			ai_dram_addr = data & 0xfffff8;
			break;

		case 0x04/4:        // AI_LEN_REG
			ai_len = data & 0x3ffff;        // Hardware v2.0 has 18 bits, v1.0 has 15 bits
			ai_fifo_push(ai_dram_addr, ai_len);
			break;

		case 0x08/4:        // AI_CONTROL_REG
			ai_control = data;
			break;

		case 0x0c/4:
			clear_rcp_interrupt(AI_INTERRUPT);
			break;

		case 0x10/4:        // AI_DACRATE_REG
		{
			ai_dacrate = data & 0x3fff;
			const double frequency = (double)DACRATE_NTSC / (double)(ai_dacrate+1);

			ai_dac[0]->set_frequency(frequency);
			ai_dac[0]->enable(1);

			ai_dac[1]->set_frequency(frequency);
			ai_dac[1]->enable(1);
			break;
		}

		case 0x14/4:        // AI_BITRATE_REG
			ai_bitrate = data & 0xf;
			break;

		default:
			logerror("ai_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, m_vr4300->pc());
			break;
	}
}


// Peripheral Interface

TIMER_CALLBACK_MEMBER(n64_periphs::pi_dma_callback)
{
	pi_dma_tick();
}

void n64_periphs::pi_dma_tick()
{
	bool update_bm = false;
	uint16_t *cart16;
	uint16_t *dram16 = (uint16_t*)m_rdram;

	uint32_t cart_addr = (pi_cart_addr & 0x0fffffff) >> 1;
	uint32_t dram_addr = (pi_dram_addr & 0x007fffff) >> 1;

	if(pi_cart_addr == 0x05000000 && dd_present)
	{
		update_bm = true;
		cart16 = (uint16_t*)dd_buffer;
		cart_addr = (pi_cart_addr & 0x000003ff) >> 1;
	}
	else if(pi_cart_addr == 0x05000400 && dd_present)
	{
		update_bm = true;
		cart16 = (uint16_t*)dd_sector_data;
		cart_addr = (pi_cart_addr & 0x000000ff) >> 1;
	}
	else if((cart_addr & 0x04000000) == 0x04000000)
	{
		cart16 = (uint16_t*)m_sram;
		cart_addr = (pi_cart_addr & 0x0001ffff) >> 1;
	}
	else if((cart_addr & 0x03000000) == 0x03000000 && dd_present)
	{
		cart16 = (uint16_t*)machine().root_device().memregion("ddipl")->base();
		cart_addr = (pi_cart_addr & 0x003fffff) >> 1;
	}
	else
	{
		cart16 = (uint16_t*)machine().root_device().memregion("user2")->base();
		cart_addr &= ((machine().root_device().memregion("user2")->bytes() >> 1) - 1);
	}

	if(pi_dma_dir == 1)
	{
		uint32_t dma_length = pi_wr_len + 1 + 1; //Round Up Nearest 2
		//logerror("PI Write, %X, %X, %X\n", pi_cart_addr, pi_dram_addr, pi_wr_len);

		if (pi_dram_addr != 0xffffffff)
		{
			for(int i = 0; i < dma_length / 2; i++)
			{
				dram16[BYTE_XOR_BE(dram_addr + i)] = cart16[BYTE_XOR_BE(cart_addr + i)];
			}

			pi_cart_addr += dma_length;
			pi_dram_addr += dma_length;
		}
	}
	else
	{
		uint32_t dma_length = pi_rd_len + 1 + 1; //Round Up Nearest 2
		//logerror("PI Read, %X, %X, %X\n", pi_cart_addr, pi_dram_addr, pi_rd_len);

		if (pi_dram_addr != 0xffffffff)
		{
			for(int i = 0; i < dma_length / 2; i++)
			{
				cart16[BYTE_XOR_BE(cart_addr + i)] = dram16[BYTE_XOR_BE(dram_addr + i)];
			}

			pi_cart_addr += dma_length;
			pi_dram_addr += dma_length;
		}
	}

	pi_status &= ~1; // Clear DMA_BUSY
	//pi_status |= 8; // Set INTERRUPT ?? Does this bit exist ??

	if(update_bm)
		dd_update_bm();

	signal_rcp_interrupt(PI_INTERRUPT);

	pi_dma_timer->adjust(attotime::never);
}

uint32_t n64_periphs::pi_reg_r(offs_t offset, uint32_t mem_mask)
{
	uint32_t ret = 0;
	switch (offset)
	{
		case 0x00/4:        // PI_DRAM_ADDR_REG
			ret = pi_dram_addr;
			break;

		case 0x04/4:        // PI_CART_ADDR_REG
			ret = pi_cart_addr;
			break;

		case 0x10/4:        // PI_STATUS_REG
			ret = pi_status;
			break;

		case 0x14/4:        // PI_BSD_DOM1_LAT
			ret = pi_bsd_dom1_lat;
			break;

		case 0x18/4:        // PI_BSD_DOM1_PWD
			ret = pi_bsd_dom1_pwd;
			break;

		case 0x1c/4:        // PI_BSD_DOM1_PGS
			ret = pi_bsd_dom1_pgs;
			break;

		case 0x20/4:        // PI_BSD_DOM1_RLS
			ret = pi_bsd_dom1_rls;
			break;

		case 0x24/4:        // PI_BSD_DOM2_LAT
			ret = pi_bsd_dom2_lat;
			break;

		case 0x28/4:        // PI_BSD_DOM2_PWD
			ret = pi_bsd_dom2_pwd;
			break;

		case 0x2c/4:        // PI_BSD_DOM2_PGS
			ret = pi_bsd_dom2_pgs;
			break;

		case 0x30/4:        // PI_BSD_DOM2_RLS
			ret = pi_bsd_dom2_rls;
			break;

		default:
			logerror("pi_reg_r: %08X, %08X at %08X\n", offset, mem_mask, m_vr4300->pc());
			break;
	}

	return ret;
}

void n64_periphs::pi_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	switch (offset)
	{
		case 0x00/4:        // PI_DRAM_ADDR_REG
		{
			pi_dram_addr = data;
			break;
		}

		case 0x04/4:        // PI_CART_ADDR_REG
		{
			pi_cart_addr = data;
			if(pi_cart_addr == 0x05000400 && dd_present)
			{
				dd_status_reg &= ~DD_ASIC_STATUS_DREQ;
				dd_status_reg &= ~DD_ASIC_STATUS_BM_INT;
				//logerror("Clearing DREQ, INT\n");
				m_vr4300->set_input_line(INPUT_LINE_IRQ1, CLEAR_LINE);
			}
			if(pi_cart_addr == 0x05000000 && dd_present)
			{
				dd_status_reg &= ~DD_ASIC_STATUS_C2_XFER;
				dd_status_reg &= ~DD_ASIC_STATUS_BM_INT;
				//logerror("Clearing C2, INT\n");
				m_vr4300->set_input_line(INPUT_LINE_IRQ1, CLEAR_LINE);
			}
			break;
		}

		case 0x08/4:        // PI_RD_LEN_REG
		{
			//logerror("Start PI Read\n");
			pi_rd_len = data;
			pi_dma_dir = 0;
			pi_status |= 1;

			attotime dma_period = attotime::from_hz(93750000) * (int)((float)(pi_rd_len + 1) * 5.08f); // Measured as between 2.53 cycles per byte and 2.55 cycles per byte
			pi_dma_timer->adjust(dma_period);
			break;
		}

		case 0x0c/4:        // PI_WR_LEN_REG
		{
			//logerror("Start PI Write\n");
			pi_wr_len = data;
			pi_dma_dir = 1;
			pi_status |= 1;

			attotime dma_period = attotime::from_hz(93750000) * (int)((float)(pi_wr_len + 1) * 5.08f); // Measured as between 2.53 cycles per byte and 2.55 cycles per byte
			pi_dma_timer->adjust(dma_period);
			break;
		}

		case 0x10/4:        // PI_STATUS_REG
		{
			if (data & 0x2)
			{
				//pi_status &= ~8; // Clear INTERRUPT ?? Does this bit exist ??
				pi_status = 0; // Reset all bits
				pi_dma_timer->adjust(attotime::never); // Cancel Pending Transfer
				clear_rcp_interrupt(PI_INTERRUPT);
			}
			break;
		}

		case 0x14/4:        // PI_BSD_DOM1_LAT
			pi_bsd_dom1_lat = data;
			break;

		case 0x18/4:        // PI_BSD_DOM1_PWD
			pi_bsd_dom1_pwd = data;
			break;

		case 0x1c/4:        // PI_BSD_DOM1_PGS
			pi_bsd_dom1_pgs = data;
			break;

		case 0x20/4:        // PI_BSD_DOM1_RLS
			pi_bsd_dom1_rls = data;
			break;

		case 0x24/4:        // PI_BSD_DOM2_LAT
			pi_bsd_dom2_lat = data;
			break;

		case 0x28/4:        // PI_BSD_DOM2_PWD
			pi_bsd_dom2_pwd = data;
			break;

		case 0x2c/4:        // PI_BSD_DOM2_PGS
			pi_bsd_dom2_pgs = data;
			break;

		case 0x30/4:        // PI_BSD_DOM2_RLS
			pi_bsd_dom2_rls = data;
			break;

		default:
			logerror("pi_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, m_vr4300->pc());
			break;
	}
}

// RDRAM Interface

uint32_t n64_periphs::ri_reg_r(offs_t offset, uint32_t mem_mask)
{
	if(offset == 0x0C/4) // RI_SELECT
	{
		/* This is to 'simulate' the time that RDRAM initialization
		would take if the RI registers were not set to skip the RDRAM
		testing during device reset.  Proper simulation would require
		emulating the RDRAM modules and bus stalls for the mips cpu.
		The cycle amount chosen represents 1/2 second, which is not
		necessarily the time for RDRAM initialization, but rather the
		time recommended for letting the SI devices settle after startup.
		This allows the initialization routines for the SI to see that a
		proper amount of time has passed since system startup. */
		m_vr4300->adjust_icount(-93750000/2);
	}

	if(offset > 0x1c/4)
	{
		logerror("ri_reg_r: %08X, %08X at %08X\n", offset, mem_mask, m_vr4300->pc());
		return 0;
	}
	return ri_regs[offset];
}

void n64_periphs::ri_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	if(offset > 0x1c/4)
	{
		logerror("ri_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, m_vr4300->pc());
		return;
	}
	COMBINE_DATA(&ri_regs[offset]);
}

// Serial Interface
uint8_t n64_periphs::calc_mempak_crc(uint8_t *buffer, int length)
{
	uint32_t crc = 0;
	uint32_t temp2 = 0;

	for(int i = 0; i <= length; i++)
	{
		for(int j = 7; j >= 0; j--)
		{
			if ((crc & 0x80) != 0)
			{
				temp2 = 0x85;
			}
			else
			{
				temp2 = 0;
			}

			crc <<= 1;

			if (i == length)
			{
				crc &= 0xff;
			}
			else
			{
				if ((buffer[i] & (1 << j)) != 0)
				{
					crc |= 0x1;
				}
			}

			crc ^= temp2;
		}
	}

	return crc;
}

static inline uint8_t convert_to_bcd(int val)
{
	return ((val / 10) << 4) | (val % 10);
}

int n64_periphs::pif_channel_handle_command(int channel, int slength, uint8_t *sdata, int rlength, uint8_t *rdata)
{
	uint8_t command = sdata[0];

	switch (command)
	{
		case 0x00:      // Read status
		case 0xff:      // Reset
		{
			switch (channel)
			{
				case 0:
				case 1:
				case 2:
				case 3:
				{
					// Read status
					switch ((machine().root_device().ioport("input")->read() >> (2 * channel)) & 3)
					{
						case 0:             //NONE (unconnected)
						case 3:             //Invalid
							return 1;

						case 1:             //JOYPAD
							rdata[0] = 0x05;
							rdata[1] = 0x00;
							rdata[2] = 0x01;
							return 0;

						case 2:             //MOUSE
							rdata[0] = 0x02;
							rdata[1] = 0x00;
							rdata[2] = 0x01;
							return 0;
					}
				}
				case 4:
				{
					// Read EEPROM status
					rdata[0] = 0x00;
					rdata[1] = (machine().root_device().ioport("input")->read() >> 8) & 0xC0;
					rdata[2] = 0x00;

					return 0;
				}
				case 5:
				{
					osd_printf_debug("EEPROM2? read status\n");
					return 1;
				}
			}

			break;
		}

		case 0x01:      // Read button values
		{
			uint16_t buttons = 0;
			int x = 0, y = 0;
			static const char *const portnames[] = { "P1", "P1_ANALOG_X", "P1_ANALOG_Y", "P1_MOUSE_X", "P1_MOUSE_Y",
													"P2", "P2_ANALOG_X", "P2_ANALOG_Y", "P2_MOUSE_X", "P2_MOUSE_Y",
													"P3", "P3_ANALOG_X", "P3_ANALOG_Y", "P3_MOUSE_X", "P3_MOUSE_Y",
													"P4", "P4_ANALOG_X", "P4_ANALOG_Y", "P4_MOUSE_X", "P4_MOUSE_Y" };

			if (slength != 1 || rlength != 4)
			{
				fatalerror("handle_pif: read button values (bytes to send %d, bytes to receive %d)\n", slength, rlength);
			}

			switch (channel)
			{
				case 0: // P1 Inputs
				case 1: // P2 Inputs
				case 2: // P3 Inputs
				case 3: // P4 Inputs
				{
					switch ((machine().root_device().ioport("input")->read() >> (2 * channel)) & 3)
					{
						case 0:         //NONE
						case 3:         //Invalid
							return 1;

						case 1:         //JOYPAD
							buttons = machine().root_device().ioport(portnames[(channel*5) + 0])->read();
							x = machine().root_device().ioport(portnames[(channel*5) + 1])->read() - 128;
							y = machine().root_device().ioport(portnames[(channel*5) + 2])->read() - 128;

							rdata[0] = (buttons >> 8) & 0xff;
							rdata[1] = (buttons >> 0) & 0xff;
							rdata[2] = (uint8_t)(x);
							rdata[3] = (uint8_t)(y);
							return 0;

						case 2:         //MOUSE
							buttons = machine().root_device().ioport(portnames[(channel*5) + 0])->read();
							x = (int16_t)machine().root_device().ioport(portnames[(channel*5) + 1 + 2])->read();// - 128;
							y = (int16_t)machine().root_device().ioport(portnames[(channel*5) + 2 + 2])->read();// - 128;

							int mouse_dx = 0;
							int mouse_dy = 0;

							if (x != mouse_x2[channel])
							{
								mouse_dx = x - mouse_x2[channel];

								if (mouse_dx > 0x40)
									mouse_dx = (0x80) - (mouse_dx - ((mouse_dx / 0x80) * 0x80));
								else if (mouse_dx < -0x40)
									mouse_dx = -(0x80) - (mouse_dx - ((mouse_dx / 0x80) * 0x80));

								mouse_x2[channel] = x;
							}

							if (y != mouse_y2[channel])
							{
								mouse_dy = y - mouse_y2[channel];

								if (mouse_dy > 0x40)
									mouse_dy = (0x80) - (mouse_dy - ((mouse_dy / 0x80) * 0x80));
								else if (mouse_dy < -0x40)
									mouse_dy = -(0x80) - (mouse_dy - ((mouse_dy / 0x80) * 0x80));

								mouse_y2[channel] = y;
							}

							if (mouse_dx)
							{
								if(mouse_dx < 0)
									mouse_dx++;
								else
									mouse_dx--;
							}

							if (mouse_dy)
							{
								if(mouse_dy < 0)
									mouse_dy++;
								else
									mouse_dy--;
							}

							rdata[0] = (buttons >> 8) & 0xff;
							rdata[1] = (buttons >> 0) & 0xff;
							rdata[2] = (uint8_t)(mouse_dx);
							rdata[3] = (uint8_t)(mouse_dy);
							return 0;

					}
				}
			}

			break;
		}

		case 0x02: // Read mempak
		{
			uint32_t address;

			address = (sdata[1] << 8) | (sdata[2]);
			address &= ~0x1f;

			if(address == 0x8000)
			{
				for(int i = 0; i < rlength-1; i++)
				{
					rdata[i] = 0x00;
				}

				rdata[rlength-1] = calc_mempak_crc(rdata, rlength-1);
				return 0;
			}
			else if(address < 0x7fe0)
			{
				for(int i = 0; i < rlength-1; i++)
				{
					rdata[i] = m_save_data.mempak[channel & 1][address+i];
				}

				rdata[rlength-1] = calc_mempak_crc(rdata, rlength-1);
				return 0;
			}

			return 1;
		}
		case 0x03: // Write mempak
		{
			uint32_t address = (sdata[1] << 8) | (sdata[2]);
			address &= ~0x1f;

			if (address < 0x8000)
			{
				for(int i = 3; i < slength; i++)
				{
					m_save_data.mempak[channel & 1][address++] = sdata[i];
				}
			}

			rdata[0] = calc_mempak_crc(&sdata[3], slength-3);

			return 0;
		}

		case 0x04:      // Read from EEPROM
		{
			if (channel != 4)
			{
				return 1;
			}

			if (slength != 2 || rlength != 8)
			{
				fatalerror("handle_pif: write EEPROM (bytes to send %d, bytes to receive %d)\n", slength, rlength);
			}

			uint16_t block_offset = sdata[1] * 8;

			for(int i=0; i < 8; i++)
			{
				rdata[i] = m_save_data.eeprom[block_offset+i];
			}

			return 0;
		}

		case 0x05:      // Write to EEPROM
		{
			if (channel != 4)
			{
				return 1;
			}

			if (slength != 10 || rlength != 1)
			{
				fatalerror("handle_pif: write EEPROM (bytes to send %d, bytes to receive %d)\n", slength, rlength);
			}

			uint16_t block_offset = sdata[1] * 8;

			for(int i = 0; i < 8; i++)
			{
				m_save_data.eeprom[block_offset+i] = sdata[2+i];
			}

			return 0;
		}

		case 0x06:      // Read RTC Status
		{
			rdata[0] = 0x00;
			rdata[1] = 0x10;
			rdata[2] = 0x00;
			return 0;
		}

		case 0x07:      // Read RTC Block
		{
			switch(sdata[1])
			{
				case 0:
					rdata[0] = 0x00;
					rdata[1] = 0x02;
					rdata[8] = 0x00;
					return 0;

				case 1:
					return 0;

				case 2:
					system_time systime;
					machine().base_datetime(systime);
					rdata[0] = convert_to_bcd(systime.local_time.second); // Seconds
					rdata[1] = convert_to_bcd(systime.local_time.minute); // Minutes
					rdata[2] = 0x80 | convert_to_bcd(systime.local_time.hour); // Hours
					rdata[3] = convert_to_bcd(systime.local_time.mday); // Day of month
					rdata[4] = convert_to_bcd(systime.local_time.weekday); // Day of week
					rdata[5] = convert_to_bcd(systime.local_time.month + 1); // Month
					rdata[6] = convert_to_bcd(systime.local_time.year % 100); // Year
					rdata[7] = convert_to_bcd(systime.local_time.year / 100); // Century
					rdata[8] = 0x00;
					return 0;
			}
			return 1;
		}

		default:
		{
			osd_printf_debug("handle_pif: unknown/unimplemented command %02X\n", command);
			return 1;
		}
	}

	return 0;
}

void n64_periphs::handle_pif()
{
	uint8_t *ram = (uint8_t*)pif_ram;
	if(pif_cmd[0x3f] == 0x1)        // only handle the command if the last byte is 1
	{
		int channel = 0;
		int end = 0;
		int cmd_ptr = 0;

		while(cmd_ptr < 0x3f && !end)
		{
			int8_t bytes_to_send = (int8_t)pif_cmd[cmd_ptr++];

			if (bytes_to_send == -2)
			{
				end = 1;
			}
			else if (bytes_to_send < 0)
			{
				// do nothing
			}
			else
			{
				if(bytes_to_send > 0 && (bytes_to_send & 0xc0) == 0)
				{
					uint8_t recv_buffer[0x40];
					uint8_t send_buffer[0x40];

					int8_t bytes_to_recv = pif_cmd[cmd_ptr++];

					if (bytes_to_recv == -2)
					{
						break; // Hack, shouldn't need to do this
					}

					for(int j = 0; j < bytes_to_send; j++)
					{
						send_buffer[j] = pif_cmd[cmd_ptr++];
					}

					int res = pif_channel_handle_command(channel, bytes_to_send, send_buffer, bytes_to_recv, recv_buffer);

					if (res == 0)
					{
						if (cmd_ptr + bytes_to_recv > 0x3f)
						{
							fatalerror("cmd_ptr overflow\n");
						}
						for(int j = 0; j < bytes_to_recv; j++)
						{
							pif_ram[cmd_ptr++] = recv_buffer[j];
						}
					}
					else if (res == 1)
					{
						int offset = 0;//bytes_to_send;
						pif_ram[cmd_ptr - offset - 2] |= 0x80;
					}
				}

				channel++;
			}
		}

		ram[0x3f ^ BYTE4_XOR_BE(0)] &= ~0x80;
	}

	/*printf("After:\n"); fflush(stdout);
	for(int i = 0; i < 0x40; i++)
	{
	    printf("%02x ", pif_ram[i]); fflush(stdout);
	    if((i & 0xf) == 0xf)
	    {
	        printf("\n"); fflush(stdout);
	    }
	}*/
}

TIMER_CALLBACK_MEMBER(n64_periphs::si_dma_callback)
{
	si_dma_tick();
}

void n64_periphs::si_dma_tick()
{
	si_dma_timer->adjust(attotime::never);
	pif_dma(si_dma_dir);
	si_status_val = 0;
	si_status_val |= 0x1000;
	signal_rcp_interrupt(SI_INTERRUPT);
}

void n64_periphs::pif_dma(int direction)
{
	if (!DWORD_ALIGNED(si_dram_addr))
	{
		fatalerror("pif_dma: si_dram_addr unaligned: %08X\n", si_dram_addr);
	}

	if (direction)      // RDRAM -> PIF RAM
	{
		uint32_t *src = m_rdram + ((si_dram_addr & 0x1fffffff) / 4);

		for(int i = 0; i < 64; i+=4)
		{
			uint32_t d = *src++;
			pif_ram[i+0] = (d >> 24) & 0xff;
			pif_ram[i+1] = (d >> 16) & 0xff;
			pif_ram[i+2] = (d >>  8) & 0xff;
			pif_ram[i+3] = (d >>  0) & 0xff;
		}

		memcpy(pif_cmd, pif_ram, 0x40);
	}
	else                // PIF RAM -> RDRAM
	{
		handle_pif();

		uint32_t *dst = m_rdram + ((si_dram_addr & 0x1fffffff) / 4);

		for(int i = 0; i < 64; i+=4)
		{
			uint32_t d = 0;
			d |= pif_ram[i+0] << 24;
			d |= pif_ram[i+1] << 16;
			d |= pif_ram[i+2] <<  8;
			d |= pif_ram[i+3] <<  0;

			*dst++ = d;
		}
	}
}

uint32_t n64_periphs::si_reg_r(offs_t offset)
{
	uint32_t ret = 0;
	switch (offset)
	{
		//case 0x00/4:      // SI_DRAM_ADDR_REG
			//return si_dram_addr;

		case 0x18/4:        // SI_STATUS_REG
			ret = si_status_val;
	}

	return ret;
}

void n64_periphs::si_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	switch (offset)
	{
		case 0x00/4:        // SI_DRAM_ADDR_REG
			si_dram_addr = data;
			break;

		case 0x04/4:        // SI_PIF_ADDR_RD64B_REG
			// PIF RAM -> RDRAM
			if(si_status_val & 1)
			{
				si_status_val |= 8; //DMA Error, overlapping request
				return; // SI Busy, ignore request
			}
			si_pif_addr = data;
			si_pif_addr_rd64b = data;
			si_dma_dir = 0;
			si_status_val |= 1;
			si_dma_timer->adjust(attotime::from_hz(50000));
			break;

		case 0x10/4:        // SI_PIF_ADDR_WR64B_REG
			// RDRAM -> PIF RAM
			if(si_status_val & 1)
			{
				si_status_val |= 8; //DMA Error, overlapping request
				return; // SI Busy, ignore request
			}
			si_pif_addr = data;
			si_pif_addr_wr64b = data;
			si_dma_dir = 1;
			si_dma_timer->adjust(attotime::from_hz(50000));
			break;

		case 0x18/4:        // SI_STATUS_REG
			si_status_val = 0;
			si_dma_timer->adjust(attotime::never);
			clear_rcp_interrupt(SI_INTERRUPT);
			break;

		default:
			logerror("si_reg_w: %08X, %08X, %08X\n", data, offset, mem_mask);
			break;
	}
}

void n64_periphs::dd_set_zone_and_track_offset()
{
	uint16_t head = (dd_track_reg & 0x1000) >> 9; // Head * 8
	uint16_t track = dd_track_reg & 0xFFF;
	uint16_t tr_off = 0;

	if(track >= 0x425)
	{
		dd_zone = 7 + head;
		tr_off = track - 0x425;
	}
	else if (track >= 0x390)
	{
		dd_zone = 6 + head;
		tr_off = track - 0x390;
	}
	else if (track >= 0x2FB)
	{
		dd_zone = 5 + head;
		tr_off = track - 0x2FB;
	}
	else if (track >= 0x266)
	{
		dd_zone = 4 + head;
		tr_off = track - 0x266;
	}
	else if (track >= 0x1D1)
	{
		dd_zone = 3 + head;
		tr_off = track - 0x1D1;
	}
	else if (track >= 0x13C)
	{
		dd_zone = 2 + head;
		tr_off = track - 0x13C;
	}
	else if (track >= 0x9E)
	{
		dd_zone = 1 + head;
		tr_off = track - 0x9E;
	}
	else
	{
		dd_zone = 0 + head;
		tr_off = track;
	}

	dd_track_offset = ddStartOffset[dd_zone] + tr_off*ddZoneSecSize[dd_zone]*SECTORS_PER_BLOCK*BLOCKS_PER_TRACK;
	//logerror("Zone %d, Head %d, Offset %x\n", dd_zone, head/8, dd_track_offset);
}

void n64_periphs::dd_update_bm()
{
	if(!(dd_buf_status_reg & DD_BMST_RUNNING))
		return;
	if(dd_write) // dd write, BM Mode 0
	{
		if(dd_current_reg == 0)
		{
			dd_current_reg += 1;
			dd_status_reg |= DD_ASIC_STATUS_DREQ;
		}
		else if(dd_current_reg < SECTORS_PER_BLOCK)
		{
			dd_write_sector();
			dd_current_reg += 1;
			dd_status_reg |= DD_ASIC_STATUS_DREQ;
		}
		else if(dd_current_reg < SECTORS_PER_BLOCK + 1)
		{
			if(dd_buf_status_reg & DD_BMST_BLOCKS)
			{
				dd_write_sector();
				dd_current_reg += 1;
				//logerror("DD Write, Start Next Block\n");
				dd_start_block = 1 - dd_start_block;
				dd_current_reg = 1;
				dd_buf_status_reg &= ~DD_BMST_BLOCKS;
				dd_status_reg |= DD_ASIC_STATUS_DREQ;
			}
			else
			{
				dd_write_sector();
				dd_current_reg += 1;
				dd_buf_status_reg &= ~DD_BMST_RUNNING;
			}
		}
		else
		{
			logerror("DD Write, Sector Overrun\n");
		}
		//logerror("DD Write, Sending Interrupt\n");
		dd_status_reg |= DD_ASIC_STATUS_BM_INT;
		m_vr4300->set_input_line(INPUT_LINE_IRQ1, ASSERT_LINE);
		return;
	}
	else // dd read, BM Mode 1
	{
		if(((dd_track_reg & 0x1FFF) == 6) && (dd_start_block == 0) && ((machine().root_device().ioport("input")->read() & 0x0100) == 0x0000))
		{
			//only fail read LBA 12 if retail disk drive
			dd_status_reg &= ~DD_ASIC_STATUS_DREQ;
			dd_buf_status_reg |= DD_BMST_MICRO_STATUS;
		}
		else if(dd_current_reg < SECTORS_PER_BLOCK)
		{
			dd_read_sector();
			dd_current_reg += 1;
			dd_status_reg |= DD_ASIC_STATUS_DREQ;
		}
		else if(dd_current_reg < SECTORS_PER_BLOCK + 4)
		{
			dd_read_C2();
			dd_current_reg += 1;
			if(dd_current_reg == SECTORS_PER_BLOCK + 4)
				dd_status_reg |= DD_ASIC_STATUS_C2_XFER;
		}
		else if(dd_current_reg == SECTORS_PER_BLOCK + 4) // Gap Sector
		{
			if(dd_buf_status_reg & DD_BMST_BLOCKS)
			{
				//logerror("DD Read, Start Next Block\n");
				dd_start_block = 1 - dd_start_block;
				dd_current_reg = 0;
				dd_buf_status_reg &= ~DD_BMST_BLOCKS;
			}
			else
			{
				dd_buf_status_reg &= ~DD_BMST_RUNNING;
			}
		}
		else
		{
			logerror("DD Read, Sector Overrun\n");
		}
		//logerror("DD Read, Sending Interrupt\n");
		dd_status_reg |= DD_ASIC_STATUS_BM_INT;
		m_vr4300->set_input_line(INPUT_LINE_IRQ1, ASSERT_LINE);
		return;
	}
}

void n64_periphs::dd_write_sector()
{
	uint8_t* sector;

	sector = (uint8_t*)machine().root_device().memregion("disk")->base();
	sector += dd_track_offset;
	sector += dd_start_block * SECTORS_PER_BLOCK * ddZoneSecSize[dd_zone];
	sector += (dd_current_reg - 1) * ddZoneSecSize[dd_zone];

	//logerror("Write Block %d, Sector %d\n", dd_start_block, dd_current_reg - 1);

	for(int i = 0; i < ddZoneSecSize[dd_zone]/4; i++)
	{
		sector[i*4 + 0] = (dd_sector_data[i] >> 24) & 0xFF;
		sector[i*4 + 1] = (dd_sector_data[i] >> 16) & 0xFF;
		sector[i*4 + 2] = (dd_sector_data[i] >> 8) & 0xFF;
		sector[i*4 + 3] = (dd_sector_data[i] >> 0) & 0xFF;
	}
	return;
}

void n64_periphs::dd_read_sector()
{
	uint8_t* sector;

	sector = (uint8_t*)machine().root_device().memregion("disk")->base();
	sector += dd_track_offset;
	sector += dd_start_block * SECTORS_PER_BLOCK * ddZoneSecSize[dd_zone];
	sector += (dd_current_reg) * (dd_sector_size + 1);

	//logerror("Read Block %d, Sector %d\n", dd_start_block, dd_current_reg);

	for(int i = 0; i < (dd_sector_size + 1)/4; i++)
	{
		dd_sector_data[i] = sector[(i*4 + 0)] << 24 | sector[(i*4 + 1)] << 16 |
							sector[(i*4 + 2)] << 8  | sector[(i*4 + 3)];
	}
	return;
}

void n64_periphs::dd_read_C2()
{
	for(int i = 0; i < ddZoneSecSize[dd_zone]/4; i++)
		dd_buffer[(dd_current_reg - SECTORS_PER_BLOCK)*0x40 + i] = 0;
	//logerror("Read C2, Sector %d", dd_current_reg);
	return;
}

uint32_t n64_periphs::dd_reg_r(offs_t offset)
{
	if(offset < 0x400/4)
	{
		return dd_buffer[offset];
	}

	if(offset < 0x500/4)
	{
		return dd_sector_data[(offset - 0x400/4)];
	}

	if((offset < 0x5C0/4) && (0x580/4 <= offset))
	{
		return dd_ram_seq_data[(offset - 0x580/4)];
	}

	offset -= 0x500/4;

	uint32_t ret = 0;
	switch(offset)
	{
		case 0x00/4: // DD Data
			ret = dd_data_reg;
			break;

		case 0x04/4: // ??
			break;

		case 0x08/4: // DD Status
			if(disk_present)
				dd_status_reg |= DD_ASIC_STATUS_DISK;
			else
				dd_status_reg &= ~DD_ASIC_STATUS_DISK;
			ret = dd_status_reg;
			// For Read, Gap Sector
			if((dd_status_reg & DD_ASIC_STATUS_BM_INT) && (SECTORS_PER_BLOCK < dd_current_reg))
			{
				dd_status_reg &= ~DD_ASIC_STATUS_BM_INT;
				//logerror("DD Read Gap, Clearing INT\n");
				m_vr4300->set_input_line(INPUT_LINE_IRQ1, CLEAR_LINE);
				dd_update_bm();
			}
			break;

		case 0x0c/4: // Current Track
			ret = dd_track_reg;
			break;

		case 0x10/4: // Transfer Buffer Status
			ret = dd_buf_status_reg;
			break;

		case 0x14/4: // Sector Error
			ret = dd_sector_err_reg;
			break;

		case 0x18/4: // Sequence Status
			ret = dd_seq_status_reg;
			break;

		case 0x1c/4: // Sequence Control
			ret = dd_seq_ctrl_reg;
			break;
		case 0x40/4: // ASIC ID
			if ((machine().root_device().ioport("input")->read() & 0x0100) == 0x0000)
				ret = 0x00030000; // Japan Retail Drive
			else
				ret = 0x00040000; // Development Drive
			break;
	}

	//logerror("dd_reg_r: %08x (%08x)\n", offset << 2, ret);
	return ret;
}

void n64_periphs::dd_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	//logerror("dd_reg_w: %08X, %08X, %08X\n", data, offset << 2, mem_mask);

	if(offset < 0x400/4)
	{
		COMBINE_DATA(&dd_buffer[offset]);
		return;
	}

	if(offset < 0x500/4)
	{
		COMBINE_DATA(&dd_sector_data[(offset - 0x400/4)]);
		return;
	}

	if((offset < 0x5C0/4) && (0x580/4 <= offset))
	{
		COMBINE_DATA(&dd_ram_seq_data[(offset - 0x580/4)]);
		return;
	}

	offset -= 0x500/4;

	switch(offset)
	{
		case 0x00/4: // DD Data
			dd_data_reg = data;
			break;

		case 0x08/4: // DD Command
			switch((data >> 16) & 0xff)
			{
				case 0x01: // Seek Read
					dd_track_reg = dd_data_reg >> 16;
					//logerror("dd command: Seek Read %d\n", dd_track_reg);
					dd_set_zone_and_track_offset();
					dd_track_reg |= DD_TRACK_INDEX_LOCK;
					dd_write = false;
					break;
				case 0x02: // Seek Write
					dd_track_reg = dd_data_reg >> 16;
					//logerror("dd command: Seek Write %d\n", dd_track_reg);
					dd_set_zone_and_track_offset();
					dd_track_reg |= DD_TRACK_INDEX_LOCK;
					dd_write = true;
					break;
				case 0x03: // Re-Zero / Recalibrate
					//logerror("dd command: Re-Zero\n");
					break;
				case 0x04: // Engage Brake
					//logerror("dd command: Engage Brake\n");
					break;
				case 0x05: // Start Motor
					//logerror("dd command: Start Motor\n");
					break;
				case 0x06: // Set Standby Time
					//logerror("dd command: Set Standby Time\n");
					break;
				case 0x07: // Set Sleep Time
					//logerror("dd command: Set Sleep Time\n");
					break;
				case 0x08: // Clear Disk Change Flag
					//logerror("dd command: Clear Disk Change Flag\n");
					break;
				case 0x09: // Clear Reset Flag
					//logerror("dd command: Clear Reset Flag\n");
					break;
				case 0x0B: // Select Disk Type
					//logerror("dd command: Select Disk Type\n");
					break;
				case 0x0C: // ASIC Command Inquiry
					//logerror("dd command: ASIC Command Inquiry\n");
					break;
				case 0x0D: // Standby Mode (?)
					//logerror("dd command: Standby Mode(?)\n");
					break;
				case 0x0E: // (Track Seek) Index Lock Retry
					//logerror("dd command: Index Lock Retry\n");
					break;
				case 0x0F: // Set RTC Year / Month
					//logerror("dd command: Set RTC Year / Month\n");
					break;
				case 0x10: // Set RTC Day / Hour
					//logerror("dd command: Set RTC Day / Hour\n");
					break;
				case 0x11: // Set RTC Minute / Second
					//logerror("dd command: Set RTC Minute / Second\n");
					break;
				case 0x12: // Read RTC Month / Year
				{
					//logerror("dd command: Read RTC Month / Year\n");

					system_time systime;
					machine().base_datetime(systime);

					dd_data_reg = (convert_to_bcd(systime.local_time.year % 100) << 24) | (convert_to_bcd(systime.local_time.month + 1) << 16);
					break;
				}

				case 0x13: // Read RTC Hour / Day
				{
					//logerror("dd command: Read RTC Hour / Day\n");

					system_time systime;
					machine().base_datetime(systime);

					dd_data_reg = (convert_to_bcd(systime.local_time.mday) << 24) | (convert_to_bcd(systime.local_time.hour) << 16);
					break;
				}

				case 0x14: // Read RTC Minute / Second
				{
					//logerror("dd command: Read RTC Minute / Second\n");

					system_time systime;
					machine().base_datetime(systime);

					dd_data_reg = (convert_to_bcd(systime.local_time.minute) << 24) | (convert_to_bcd(systime.local_time.second) << 16);
					break;
				}
				case 0x15: // Set LED On/Off Time
				{
					//logerror("dd command: Set LED On/Off Time\n");
					break;
				}
				case 0x1B: // Disk Inquiry
				{
					//logerror("dd command: Disk Inquiry\n");
					dd_data_reg = 0x00000000;
					break;
				}
			}
			//logerror("Sending MECHA Int\n");
			dd_status_reg |= DD_ASIC_STATUS_MECHA_INT;
			m_vr4300->set_input_line(INPUT_LINE_IRQ1, ASSERT_LINE);
			break;

		case 0x10/4: // BM Status
			//logerror("dd BM Status write\n");
			dd_start_sector = (data >> 16) & 0xFF;
			if(dd_start_sector == 0x00)
			{
				dd_start_block = 0;
				dd_current_reg = 0;
			}
			else if (dd_start_sector == 0x5A)
			{
				dd_start_block = 1;
				dd_current_reg = 0;
			}
			else
			{
				logerror("dd: start sector not aligned\n");
			}
			if(data & DD_BM_XFERBLOCKS)
				dd_buf_status_reg |= DD_BMST_BLOCKS;
			if(data & DD_BM_MECHA_INT_RESET)
				dd_status_reg &= ~DD_ASIC_STATUS_MECHA_INT;
			if(data & DD_BM_RESET)
				dd_bm_reset_held = true;
			if(!(data & DD_BM_RESET) && dd_bm_reset_held)
			{
				dd_bm_reset_held = false;
				dd_status_reg &= ~DD_ASIC_STATUS_BM_INT;
				dd_status_reg &= ~DD_ASIC_STATUS_BM_ERROR;
				dd_status_reg &= ~DD_ASIC_STATUS_DREQ;
				dd_status_reg &= ~DD_ASIC_STATUS_C2_XFER;
				dd_buf_status_reg = 0;
				dd_current_reg = 0;
				dd_start_block = 0;
				//logerror("dd: BM RESET\n");
			}
			if(!(dd_status_reg & DD_ASIC_STATUS_BM_INT) && !(dd_status_reg & DD_ASIC_STATUS_MECHA_INT))
			{
				//logerror("DD Status, Clearing INT\n");
				m_vr4300->set_input_line(INPUT_LINE_IRQ1, CLEAR_LINE);
			}
			if(data & DD_BM_START)
			{
				if(dd_write && (data & DD_BM_MODE))
					popmessage("Attempt to write disk with BM Mode 1\n");
				if(!dd_write && !(data & DD_BM_MODE))
					popmessage("Attempt to read disk with BM Mode 0\n");
				dd_buf_status_reg |= DD_BMST_RUNNING;
				//logerror("dd: Start BM\n");
				dd_update_bm();
			}

			break;

		case 0x1c/4: // Sequence Control
			dd_seq_ctrl_reg = data;
			break;
		case 0x28/4: // Host Sector Byte
			dd_sector_size = (data >> 16) & 0xFF;
			if((dd_sector_size + 1) != ddZoneSecSize[dd_zone])
				popmessage("Sector size %d set different than expected %d\n", dd_sector_size + 1, ddZoneSecSize[dd_zone]);
			break;
		case 0x30/4: // Sector Byte
			dd_sectors_per_block = (data >> 24) & 0xFF;
			if(dd_sectors_per_block != SECTORS_PER_BLOCK + 4)
				popmessage("Sectors per block %d set different than expected %d\n", dd_sectors_per_block, SECTORS_PER_BLOCK + 4);
	}
}

uint32_t n64_periphs::pif_ram_r(offs_t offset, uint32_t mem_mask)
{
	if(!machine().side_effects_disabled())
	{
		if( offset == ( 0x24 / 4 ) )
		{
			cic_status = 0x00000080;
		}
		if( offset == ( 0x3C / 4 ) )
		{
			return cic_status;
		}
	}
	return ( ( pif_ram[offset*4+0] << 24 ) | ( pif_ram[offset*4+1] << 16 ) | ( pif_ram[offset*4+2] <<  8 ) | ( pif_ram[offset*4+3] <<  0 ) ) & mem_mask;
}

void n64_periphs::pif_ram_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
	if( ACCESSING_BITS_24_31 )
	{
		pif_ram[offset*4+0] = ( data >> 24 ) & 0x000000ff;
	}
	if( ACCESSING_BITS_16_23 )
	{
		pif_ram[offset*4+1] = ( data >> 16 ) & 0x000000ff;
	}
	if( ACCESSING_BITS_8_15 )
	{
		pif_ram[offset*4+2] = ( data >>  8 ) & 0x000000ff;
	}
	if( ACCESSING_BITS_0_7 )
	{
		pif_ram[offset*4+3] = ( data >>  0 ) & 0x000000ff;
	}

	signal_rcp_interrupt(SI_INTERRUPT);
}

void n64_state::n64_machine_stop()
{
	if (m_rcp_periphs->m_nvram_image == nullptr)
		return;

	device_image_interface *image = dynamic_cast<device_image_interface *>(m_rcp_periphs->m_nvram_image);

	uint8_t data[0x30800];
	if (m_sram == nullptr)
	{
		memset(data, 0, 0x20000);
	}
	else
	{
		memcpy(data, m_sram, 0x20000);
	}
	memcpy(data + 0x20000, m_rcp_periphs->m_save_data.eeprom, 0x800);
	memcpy(data + 0x20800, m_rcp_periphs->m_save_data.mempak[0], 0x8000);
	memcpy(data + 0x28800, m_rcp_periphs->m_save_data.mempak[1], 0x8000);
	image->battery_save(data, 0x30800);
}

void n64_state::machine_start()
{
	m_vr4300->mips3drc_set_options(MIPS3DRC_COMPATIBLE_OPTIONS);

	/* configure fast RAM regions */
	//m_vr4300->add_fastram(0x00000000, 0x007fffff, false, m_rdram);

	m_rsp->rspdrc_set_options(RSPDRC_STRICT_VERIFY);
	m_rsp->rspdrc_flush_drc_cache();
	m_rsp->rsp_add_dmem(m_rsp_dmem);
	m_rsp->rsp_add_imem(m_rsp_imem);

	/* add a hook for battery save */
	machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(&n64_state::n64_machine_stop,this));
}

void n64_state::machine_reset()
{
	m_rsp->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
}