summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/smpc.cpp
blob: 749f5bc8f8bfb4f0ca77696bc72164ab52d6032d (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
                    
                                              










                                                                                     

                                                                                 








































































































































                                                                                      
                            
                         
                              
 
                  
                     
 






                                             
                                              
 
                                        
         

                                                                                                 
                    
                                                                                              
 
                                           


         





                                             
                                   
 
                                                                

 
                                                        
 




                                                                                        

 
                                                        
 



                                                                                       

 
                                                     
 

                                                                                                  

 
                                      
 
                                                                                        

                                                


                                          



                                                

               
                                                                

 
                                                        
 
                      
 
                                                                                                                                    

                                                           
 

                                                                
 

                                      
 





                                                                      

                                          
                                       
                                   
                         

                                                                     

 
                                                             
 
                                      
         

                                                                                                               


            

                                                                                                            

         

                                                                         
            
                                        
 

                                                                      


 
                                                       
 
              
 
                                                                                                 
 
                                      
         
                                                                   
 
                                
                                                              
 
                                                     
 
                                                                      
 

                                                                                    





                                                                                   
                                                
 
                                
                                                         
 
                                 
                                                            
 


                                                                                            
 

                                                                                                                               

                                                                                 
                    
                                                

                                                  
                                                            
                                           
                                 
         
                                          
         



                                                                                                                                                   
         


                                                                                                                                             

                                       
         

 
  









                                                                                      








                                                                                         

                                                                                    
                                                                                      



                                                                                                

  
                                                         
 
                                                                                              
 
                        
                                             
 
                                                                                                                                                        
 

                                                                  
 


                                                                                                 
 


                                                 
         
                                                 








                                                                                         
                                                 



                                                                                         
         
 
                                      
         

                                                                                                               


            

                                                                                                            

         

                                                                         
            
                                        
 

                                                                      

 
                                                          
 
                                      

                 
                              
 
                                                                                                                            
 
                                        
                                                                      
 
                                                               
 
                                                         
 

                                                                                                    





                                                                                                   
                                                        

                                        
                                                                 

                                         
                                                                    

                 


                                                                                            
 

                                                                                 
                    
                                                
 
                                                  
                                       
                                           
                                 
         
                                          
         



                                                                                                                                               


            
                                                                                                        

         

 
                                   
 


                        
                                                    

 
                                        
 


                        
                                                

 
                                 
 
                                             
                                                              

 
                                                   
 
                                                                                        
 
                            
                                          
                                       
                                   
                         
 
                                                             

 
 




                                                                  

                                             
                     


                                             
                                                                                       
 



                                                                  
                                         
                              
                                        

                          

                                                                                                                                                                   


                              


                                                                                           
                                                                                                                                                                      
                              
                                     


                                                                           
                                                                                                                                                           
                              


                                                                                                   
                                              
                                                                     
                                            


                              
                                                                                                                                                                              

                                                                                                          




                                                                                                                            


                                                                                 
 
                                                                                                                                                                                                                                 


                                    
                             
                         
                                                                                                                                                                  

                         
                                   
 
                                   
 
                                                                      
                                            
 
                                                              
                                                                 
                                              
 


                                                                      
 
                                                
                                                                               
                         
 

                                  
                                                                                                                                                                                        


                            

                                                                                                                                                                                                       
                         



                                                                 
                                         



                                                                       
                                              


                                                                    
                                       


                              
                                          

                                                                                                                                                                   

                              
                                                                                                                                              
         

 





                                             
                                        
 





                                            
                                                              

                                       
                                        

                           
                                        

                                      
                                                     

                                      
                                                           



                           
                                         
 

                                                         
 
                                                                                           

                                        
                                                
 

                                                                                        
                                        



                                                                                

                                                         



                                                                                   


                                                                                                                                                                                                    



                         

                                     
                                               

                                                                 
                                                                                                                                                              
                 

                                                                   




                                                              
                                     



                          





                                           



                                                                              
 
                                                  
 
                                            




                          


                                                              
                                                             
 
                                                                                    


                                                                                                                                                                               
 
                                                                        
                                            




                          


                                                                          

                                                




                                                                   

                                               


         





                                             
                                                         
 
                        
                                                                                    
 
                               



                                                   
 
                                                                                                                
 
                   
         

                                                                                                                      
                                      
                                    
                                                    

                              
                                      
                                                    
                                                                                                                     

                                                                  
                              
                       
                                      
                                    
                                                                      
                              
                       
                                      
                                                    



                                                                             

                              
 


                   
                                                     
 
                                                                                        
                                                 
 
                               



                                                   


                                                                                                
                                                                      


                                           
 
                                




                                                                                 
                                                              
 
                           
                                        
 
                           
         
                                                                                                         
                                        
         


                                                          
                                                                                           
                 
                                        
 
                                                                                                                                                 




                                                                                                        
                                                                               
 

                                              
                                                                 






                                                                                                                           


                 
                                                                                                                                                                                         
 


                           
                                            
 
                                                                                                                      
 

                                                         
 
                                        
                                                
 
                                                                                        
         
                                        
                 

                                       
                                                                                          

                                                         


                                            
                                                                                             
                                                                                                                                                                                                

                                                                              
                         
                 

         
                           
         
                                               
 
                                                                 
                                                                                                                                                                                    
                 

                                                                                   

                                                              

         
                           
                                                        
 
                                   
                                          
 
                                   
                                          

                          
                                          

                          
                                          
 

                          

                                                




                                                                   

                                               

         
// license:LGPL-2.1+
// copyright-holders:Angelo Salese, R. Belmont
/************************************************************************************

Sega Saturn SMPC - System Manager and Peripheral Control MCU simulation

The SMPC is actually a 4-bit Hitachi HD404920FS MCU, labeled with a Sega custom
315-5744 (that needs decapping)

MCU simulation by Angelo Salese & R. Belmont

TODO:
- timings;
- fix intback issue with inputs (according to the docs, it should fall in between
  VBLANK-IN and OUT, for obvious reasons);
- clean-ups;

*************************************************************************************/
/* SMPC Addresses

00
01 -w  Input Register 0 (IREG)
02
03 -w  Input Register 1
04
05 -w  Input Register 2
06
07 -w  Input Register 3
08
09 -w  Input Register 4
0a
0b -w  Input Register 5
0c
0d -w  Input Register 6
0e
0f
10
11
12
13
14
15
16
17
18
19
1a
1b
1c
1d
1e
1f -w  Command Register (COMREG)
20
21 r-  Output Register 0 (OREG)
22
23 r-  Output Register 1
24
25 r-  Output Register 2
26
27 r-  Output Register 3
28
29 r-  Output Register 4
2a
2b r-  Output Register 5
2c
2d r-  Output Register 6
2e
2f r-  Output Register 7
30
31 r-  Output Register 8
32
33 r-  Output Register 9
34
35 r-  Output Register 10
36
37 r-  Output Register 11
38
39 r-  Output Register 12
3a
3b r-  Output Register 13
3c
3d r-  Output Register 14
3e
3f r-  Output Register 15
40
41 r-  Output Register 16
42
43 r-  Output Register 17
44
45 r-  Output Register 18
46
47 r-  Output Register 19
48
49 r-  Output Register 20
4a
4b r-  Output Register 21
4c
4d r-  Output Register 22
4e
4f r-  Output Register 23
50
51 r-  Output Register 24
52
53 r-  Output Register 25
54
55 r-  Output Register 26
56
57 r-  Output Register 27
58
59 r-  Output Register 28
5a
5b r-  Output Register 29
5c
5d r-  Output Register 30
5e
5f r-  Output Register 31
60
61 r-  SR
62
63 rw  SF
64
65
66
67
68
69
6a
6b
6c
6d
6e
6f
70
71
72
73
74
75 rw PDR1
76
77 rw PDR2
78
79 -w DDR1
7a
7b -w DDR2
7c
7d -w IOSEL2/1
7e
7f -w EXLE2/1
*/

#include "emu.h"
#include "coreutil.h"
#include "includes/saturn.h"
#include "machine/smpc.h"
#include "machine/eepromser.h"

#define LOG_SMPC 0
#define LOG_PAD_CMD 0


/********************************************
 *
 * Bankswitch code for ST-V Multi Cart mode
 *
 *******************************************/

void saturn_state::stv_select_game(int gameno)
{
	if (m_prev_bankswitch != gameno)
	{
		if (m_cart_reg[gameno] && m_cart_reg[gameno]->base())
			memcpy(memregion("abus")->base(), m_cart_reg[gameno]->base(), 0x3000000);
		else
			memset(memregion("abus")->base(), 0x00, 0x3000000); // TODO: 1-filled?

		m_prev_bankswitch = gameno;
	}
}

/********************************************
 *
 * Command functions
 *
 *******************************************/

void saturn_state::smpc_master_on()
{
	m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
}

TIMER_CALLBACK_MEMBER( saturn_state::smpc_slave_enable )
{
	m_slave->set_input_line(INPUT_LINE_RESET, param ? ASSERT_LINE : CLEAR_LINE);
	m_smpc.OREG[31] = param + 0x02; //read-back for last command issued
	m_smpc.SF = 0x00; //clear hand-shake flag
	m_smpc.slave_on = param;
//  printf("%d %d\n",machine().first_screen()->hpos(),machine().first_screen()->vpos());
}

TIMER_CALLBACK_MEMBER( saturn_state::smpc_sound_enable )
{
	m_audiocpu->set_input_line(INPUT_LINE_RESET, param ? ASSERT_LINE : CLEAR_LINE);
	m_en_68k = param ^ 1;
	m_smpc.OREG[31] = param + 0x06; //read-back for last command issued
	m_smpc.SF = 0x00; //clear hand-shake flag
}

TIMER_CALLBACK_MEMBER( saturn_state::smpc_cd_enable )
{
	m_smpc.OREG[31] = param + 0x08; //read-back for last command issued
	m_smpc.SF = 0x08; //clear hand-shake flag (TODO: diagnostic wants this to have bit 3 high)
}

void saturn_state::smpc_system_reset()
{
	/*Only backup ram and SMPC ram are retained after that this command is issued.*/
	memset(m_scu_regs.get() ,0x00,0x000100);
	memset(m_scsp_regs.get(),0x00,0x001000);
	memset(m_sound_ram,0x00,0x080000);
	memset(m_workram_h,0x00,0x100000);
	memset(m_workram_l,0x00,0x100000);
	memset(m_vdp2_regs.get(),0x00,0x040000);
	memset(m_vdp2_vram.get(),0x00,0x100000);
	memset(m_vdp2_cram.get(),0x00,0x080000);
	memset(m_vdp1_vram.get(),0x00,0x100000);
	//A-Bus

	m_maincpu->set_input_line(INPUT_LINE_RESET, PULSE_LINE);
}

TIMER_CALLBACK_MEMBER( saturn_state::smpc_change_clock )
{
	uint32_t xtal;

	if(LOG_SMPC) printf ("Clock change execute at (%d %d)\n",machine().first_screen()->hpos(),machine().first_screen()->vpos());

	xtal = param ? MASTER_CLOCK_320 : MASTER_CLOCK_352;

	machine().device("maincpu")->set_unscaled_clock(xtal/2);
	machine().device("slave")->set_unscaled_clock(xtal/2);

	m_vdp2.dotsel = param ^ 1;
	stv_vdp2_dynamic_res_change();

	m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
	if(!m_NMI_reset)
		m_maincpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE);
	m_slave->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
	m_slave->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
	m_audiocpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);

	/* put issued command in OREG31 */
	m_smpc.OREG[31] = 0x0e + param;
	/* clear hand-shake flag */
	m_smpc.SF = 0x00;

	/* TODO: VDP1 / VDP2 / SCU / SCSP default power ON values? */
}

TIMER_CALLBACK_MEMBER( saturn_state::stv_intback_peripheral )
{
	if (m_smpc.intback_stage == 2)
	{
		m_smpc.SR = (0x80 | m_smpc.pmode);    // pad 2, no more data, echo back pad mode set by intback
		m_smpc.intback_stage = 0;
	}
	else
	{
		m_smpc.SR = (0xc0 | m_smpc.pmode);    // pad 1, more data, echo back pad mode set by intback
		m_smpc.intback_stage ++;
	}

	if(!(m_scu.ism & IRQ_SMPC))
		m_maincpu->set_input_line_and_vector(8, HOLD_LINE, 0x47);
	else
		m_scu.ist |= (IRQ_SMPC);

	m_smpc.OREG[31] = 0x10; /* callback for last command issued */
	m_smpc.SF = 0x00;    /* clear hand-shake flag */
}


TIMER_CALLBACK_MEMBER( saturn_state::stv_smpc_intback )
{
	int i;

//  printf("%02x %02x %02x\n",m_smpc.intback_buf[0],m_smpc.intback_buf[1],m_smpc.intback_buf[2]);

	if(m_smpc.intback_buf[0] != 0)
	{
		m_smpc.OREG[0] = (0x80) | ((m_NMI_reset & 1) << 6);

		for(i=0;i<7;i++)
			m_smpc.OREG[1+i] = m_smpc.rtc_data[i];

		m_smpc.OREG[8]=0x00;  // CTG0 / CTG1?

		m_smpc.OREG[9]=0x00;  // TODO: system region on Saturn

		m_smpc.OREG[10]= 0 << 7 |
								m_vdp2.dotsel << 6 |
								1 << 5 |
								1 << 4 |
								0 << 3 | //MSHNMI
								1 << 2 |
								0 << 1 | //SYSRES
								0 << 0;  //SOUNDRES
		m_smpc.OREG[11]= 0 << 6; //CDRES

		for(i=0;i<4;i++)
			m_smpc.OREG[12+i]=m_smpc.SMEM[i];

		for(i=0;i<15;i++)
			m_smpc.OREG[16+i]=0xff; // undefined

		m_smpc.intback_stage = (m_smpc.intback_buf[1] & 8) >> 3; // first peripheral
		m_smpc.SR = 0x40 | m_smpc.intback_stage << 5;
		m_smpc.pmode = m_smpc.intback_buf[0]>>4;

		//  /*This is for RTC,cartridge code and similar stuff...*/
		//if(LOG_SMPC) printf ("Interrupt: System Manager (SMPC) at scanline %04x, Vector 0x47 Level 0x08\n",scanline);
		if(!(m_scu.ism & IRQ_SMPC))
			m_maincpu->set_input_line_and_vector(8, HOLD_LINE, 0x47);
		else
			m_scu.ist |= (IRQ_SMPC);

		/* put issued command in OREG31 */
		m_smpc.OREG[31] = 0x10; // TODO: doc says 0?
		/* clear hand-shake flag */
		m_smpc.SF = 0x00;
	}
	else if(m_smpc.intback_buf[1] & 8)
	{
		m_smpc.intback_stage = (m_smpc.intback_buf[1] & 8) >> 3; // first peripheral
		m_smpc.SR = 0x40;
		m_smpc.OREG[31] = 0x10;
		machine().scheduler().timer_set(attotime::from_usec(0), timer_expired_delegate(FUNC(saturn_state::stv_intback_peripheral),this),0);
	}
	else
	{
		/* Shienryu calls this, it would be plainly illegal on Saturn, I'll just return the command and clear the hs flag for now. */
		m_smpc.OREG[31] = 0x10;
		m_smpc.SF = 0x00;
	}
}

/*
    [0] port status:
        0x04 Sega-tap
        0x16 Multi-tap
        0x2x clock serial peripheral
        0xf0 peripheral isn't connected
        0xf1 peripheral is connected
    [1] Peripheral ID (note: lowest four bits determines the size of the input packet)
        0x02 digital pad
        0x25 (tested by Game Basic?)
        0x34 keyboard

 Lower 4 bits of the port status tell the number of controllers to check for the port
 Lower 4 bits of the peripheral ID tell the number of registers used by each controller
 For multitap / segatap, we have implemented the following logic:
 SMPC reads in sequence
 - status for port 1
 - ID first controller, followed by the number of reads needed by the plugged controller
 - ID second controller, followed by the number of reads needed by the plugged controller
 - and so on... until the 4th (for SegaTap) or 6th (for Multitap) controller is read
 TODO: how does the multitap check if a controller is connected? does it ask for the
 controller status of each subport? how does this work exactly?
 currently, there is a small problem in some specific controller config which seems to
 lose track of one controller. E.g. if I put multitap in port2 with inserted joy1, joy2 and joy4
 it does not see joy4 controller, but if I put joy1, joy2, joy4 and joy5 it sees
 all four of them. The same happens if I skip controllers with id = 0xff...
 how did a real unit behave in this case?
*/

TIMER_CALLBACK_MEMBER( saturn_state::intback_peripheral )
{
//  if (LOG_SMPC) logerror("SMPC: providing PAD data for intback, pad %d\n", intback_stage-2);

	// doesn't work?
	//pad_num = m_smpc.intback_stage - 1;

	if(LOG_PAD_CMD) printf("%d %d %d\n", m_smpc.intback_stage - 1, machine().first_screen()->vpos(), (int)machine().first_screen()->frame_number());

	uint8_t status1 = m_ctrl1 ? m_ctrl1->read_status() : 0xf0;
	uint8_t status2 = m_ctrl2 ? m_ctrl2->read_status() : 0xf0;

	uint8_t reg_offset = 0;
	uint8_t ctrl1_offset = 0;     // this is used when there is segatap or multitap connected
	uint8_t ctrl2_offset = 0;     // this is used when there is segatap or multitap connected

	m_smpc.OREG[reg_offset++] = status1;
	// read ctrl1
	for (int i = 0; i < (status1 & 0xf); i++)
	{
		uint8_t id = m_ctrl1->read_id(i);
		m_smpc.OREG[reg_offset++] = id;
		for (int j = 0; j < (id & 0xf); j++)
			m_smpc.OREG[reg_offset++] = m_ctrl1->read_ctrl(j + ctrl1_offset);
		ctrl1_offset += (id & 0xf);
	}
	m_smpc.OREG[reg_offset++] = status2;
	// read ctrl2
	for (int i = 0; i < (status2 & 0xf); i++)
	{
		uint8_t id = m_ctrl2->read_id(i);
		m_smpc.OREG[reg_offset++] = id;
		for (int j = 0; j < (id & 0xf); j++)
			m_smpc.OREG[reg_offset++] = m_ctrl2->read_ctrl(j + ctrl2_offset);
		ctrl2_offset += (id & 0xf);
	}

	if (m_smpc.intback_stage == 2)
	{
		m_smpc.SR = (0x80 | m_smpc.pmode);    // pad 2, no more data, echo back pad mode set by intback
		m_smpc.intback_stage = 0;
	}
	else
	{
		m_smpc.SR = (0xc0 | m_smpc.pmode);    // pad 1, more data, echo back pad mode set by intback
		m_smpc.intback_stage ++;
	}

	if(!(m_scu.ism & IRQ_SMPC))
		m_maincpu->set_input_line_and_vector(8, HOLD_LINE, 0x47);
	else
		m_scu.ist |= (IRQ_SMPC);

	m_smpc.OREG[31] = 0x10; /* callback for last command issued */
	m_smpc.SF = 0x00;    /* clear hand-shake flag */
}

TIMER_CALLBACK_MEMBER( saturn_state::saturn_smpc_intback )
{
	if(m_smpc.intback_buf[0] != 0)
	{
		{
			int i;

			m_smpc.OREG[0] = (0x80) | ((m_NMI_reset & 1) << 6); // bit 7: SETTIME (RTC isn't setted up properly)

			for(i=0;i<7;i++)
				m_smpc.OREG[1+i] = m_smpc.rtc_data[i];

			m_smpc.OREG[8]=0x00;  //Cartridge code?

			m_smpc.OREG[9] = m_saturn_region;

			m_smpc.OREG[10]= 0 << 7 |
										m_vdp2.dotsel << 6 |
										1 << 5 |
										1 << 4 |
										0 << 3 | //MSHNMI
										1 << 2 |
										0 << 1 | //SYSRES
										0 << 0;  //SOUNDRES
			m_smpc.OREG[11]= 0 << 6; //CDRES

			for(i=0;i<4;i++)
				m_smpc.OREG[12+i]=m_smpc.SMEM[i];

			for(i=0;i<15;i++)
				m_smpc.OREG[16+i]=0xff; // undefined
		}

		m_smpc.intback_stage = (m_smpc.intback_buf[1] & 8) >> 3; // first peripheral
		m_smpc.SR = 0x40 | m_smpc.intback_stage << 5;
		m_smpc.pmode = m_smpc.intback_buf[0]>>4;

		if(!(m_scu.ism & IRQ_SMPC))
			m_maincpu->set_input_line_and_vector(8, HOLD_LINE, 0x47);
		else
			m_scu.ist |= (IRQ_SMPC);

		/* put issued command in OREG31 */
		m_smpc.OREG[31] = 0x10;
		/* clear hand-shake flag */
		m_smpc.SF = 0x00;
	}
	else if(m_smpc.intback_buf[1] & 8)
	{
		m_smpc.intback_stage = (m_smpc.intback_buf[1] & 8) >> 3; // first peripheral
		m_smpc.SR = 0x40;
		m_smpc.OREG[31] = 0x10;
		machine().scheduler().timer_set(attotime::from_usec(0), timer_expired_delegate(FUNC(saturn_state::intback_peripheral),this),0);
	}
	else
	{
		printf("SMPC intback bogus behaviour called %02x %02x\n",m_smpc.IREG[0],m_smpc.IREG[1]);
	}

}

void saturn_state::smpc_rtc_write()
{
	int i;

	for(i=0;i<7;i++)
		m_smpc.rtc_data[i] = m_smpc.IREG[i];
}

void saturn_state::smpc_memory_setting()
{
	int i;

	for(i=0;i<4;i++)
		m_smpc.SMEM[i] = m_smpc.IREG[i];
}

void saturn_state::smpc_nmi_req()
{
	/*NMI is unconditionally requested */
	m_maincpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE);
}

TIMER_CALLBACK_MEMBER( saturn_state::smpc_nmi_set )
{
//  printf("%d %d\n",machine().first_screen()->hpos(),machine().first_screen()->vpos());

	m_NMI_reset = param;
	/* put issued command in OREG31 */
	m_smpc.OREG[31] = 0x19 + param;
	/* clear hand-shake flag */
	m_smpc.SF = 0x00;

	//m_smpc.OREG[0] = (0x80) | ((m_NMI_reset & 1) << 6);
}


TIMER_CALLBACK_MEMBER( saturn_state::smpc_audio_reset_line_pulse )
{
	m_audiocpu->set_input_line(INPUT_LINE_RESET, PULSE_LINE);
}

/********************************************
 *
 * COMREG sub-routine
 *
 *******************************************/

void saturn_state::smpc_comreg_exec(address_space &space, uint8_t data, uint8_t is_stv)
{
	switch (data)
	{
		case 0x00:
			if(LOG_SMPC) printf ("SMPC: Master ON\n");
			smpc_master_on();
			break;
		//case 0x01: Master OFF?
		case 0x02:
		case 0x03:
			if(LOG_SMPC) printf ("SMPC: Slave %s %d %d\n",(data & 1) ? "off" : "on",machine().first_screen()->hpos(),machine().first_screen()->vpos());
			machine().scheduler().timer_set(attotime::from_usec(15), timer_expired_delegate(FUNC(saturn_state::smpc_slave_enable),this),data & 1);
			break;
		case 0x06:
		case 0x07:
			if(LOG_SMPC) printf ("SMPC: Sound %s\n",(data & 1) ? "off" : "on");

			if(!is_stv)
				machine().scheduler().timer_set(attotime::from_usec(15), timer_expired_delegate(FUNC(saturn_state::smpc_sound_enable),this),data & 1);
			break;
		/*CD (SH-1) ON/OFF */
		case 0x08:
		case 0x09:
			printf ("SMPC: CD %s\n",(data & 1) ? "off" : "on");
			machine().scheduler().timer_set(attotime::from_usec(20), timer_expired_delegate(FUNC(saturn_state::smpc_cd_enable),this),data & 1);
			break;
		case 0x0a:
		case 0x0b:
			popmessage ("SMPC: NETLINK %s, contact MAMEdev",(data & 1) ? "off" : "on");
			break;      case 0x0d:
			if(LOG_SMPC) printf ("SMPC: System Reset\n");
			smpc_system_reset();
			break;
		case 0x0e:
		case 0x0f:
			if(LOG_SMPC) printf ("SMPC: Change Clock to %s (%d %d)\n",data & 1 ? "320" : "352",machine().first_screen()->hpos(),machine().first_screen()->vpos());

			/* on ST-V timing of this is pretty fussy, you get 2 credits at start-up otherwise
			   My current theory is that SMPC first stops all CPUs until it executes the whole snippet for this,
			   and restarts them when the screen is again ready for use. I really don't think that the system
			   can do an usable mid-frame clock switching anyway.
			   */

			m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
			m_slave->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
			m_audiocpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);

			machine().scheduler().timer_set(machine().first_screen()->time_until_pos(get_vblank_start_position()*get_ystep_count(), 0), timer_expired_delegate(FUNC(saturn_state::smpc_change_clock),this),data & 1);
			break;
		/*"Interrupt Back"*/
		case 0x10:
			if(0)
			{
				printf ("SMPC: Status Acquire %02x %02x %02x %d\n",m_smpc.IREG[0],m_smpc.IREG[1],m_smpc.IREG[2],machine().first_screen()->vpos());
			}

			int timing;

			timing = 8;

			if(m_smpc.IREG[0] != 0) // non-peripheral data
				timing += 8;

			/* TODO: At vblank-out actually ... */
			if(m_smpc.IREG[1] & 8) // peripheral data
				timing += 700;

			/* TODO: check if IREG[2] is setted to 0xf0 */
			{
				int i;

				for(i=0;i<3;i++)
					m_smpc.intback_buf[i] = m_smpc.IREG[i];
			}

			if(is_stv)
			{
				machine().scheduler().timer_set(attotime::from_usec(timing), timer_expired_delegate(FUNC(saturn_state::stv_smpc_intback),this),0); //TODO: variable time
			}
			else
			{
				if(LOG_PAD_CMD) printf("INTBACK %02x %02x %d %d\n",m_smpc.IREG[0],m_smpc.IREG[1],machine().first_screen()->vpos(),(int)machine().first_screen()->frame_number());
				machine().scheduler().timer_set(attotime::from_usec(timing), timer_expired_delegate(FUNC(saturn_state::saturn_smpc_intback),this),0); //TODO: is variable time correct?
			}
			break;
		/* RTC write*/
		case 0x16:
			if(LOG_SMPC) printf("SMPC: RTC write\n");
			smpc_rtc_write();
			break;
		/* SMPC memory setting*/
		case 0x17:
			if(LOG_SMPC) printf ("SMPC: memory setting\n");
			smpc_memory_setting();
			break;
		case 0x18:
			if(LOG_SMPC) printf ("SMPC: NMI request\n");
			smpc_nmi_req();
			break;
		case 0x19:
		case 0x1a:
			/* TODO: timing */
			if(LOG_SMPC) printf ("SMPC: NMI %sable %d %d\n",data & 1 ? "Dis" : "En",machine().first_screen()->hpos(),machine().first_screen()->vpos());
			machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(saturn_state::smpc_nmi_set),this),data & 1);
			break;
		default:
			printf ("cpu '%s' (PC=%08X) SMPC: undocumented Command %02x\n", space.device().tag(), space.device().safe_pc(), data);
	}
}

/********************************************
 *
 * ST-V handlers
 *
 *******************************************/

READ8_MEMBER( saturn_state::stv_SMPC_r )
{
	int return_data = 0;

	if(!(offset & 1))
		return 0;

	if(offset >= 0x21 && offset <= 0x5f)
		return_data = m_smpc.OREG[(offset-0x21) >> 1];

	if (offset == 0x61) // TODO: SR
		return_data = m_smpc.SR;

	if (offset == 0x63)
		return_data = m_smpc.SF;

	if (offset == 0x75)//PDR1 read
		return_data = ioport("DSW1")->read();

	if (offset == 0x77)//PDR2 read
		return_data = (0xfe | m_eeprom->do_read());

	return return_data;
}

WRITE8_MEMBER( saturn_state::stv_SMPC_w )
{
	if (!(offset & 1)) // avoid writing to even bytes
		return;

//  if(LOG_SMPC) printf ("8-bit SMPC Write to Offset %02x with Data %02x\n", offset, data);

	if(offset >= 1 && offset <= 0xd)
		m_smpc.IREG[offset >> 1] = data;

	if(offset == 1) //IREG0, check if a BREAK / CONTINUE request for INTBACK command
	{
		if(m_smpc.intback_stage)
		{
			if(data & 0x40)
			{
				if(LOG_PAD_CMD) printf("SMPC: BREAK request\n");
				m_smpc.SR &= 0x0f;
				m_smpc.intback_stage = 0;
			}
			else if(data & 0x80)
			{
				if(LOG_PAD_CMD) printf("SMPC: CONTINUE request\n");
				machine().scheduler().timer_set(attotime::from_usec(700), timer_expired_delegate(FUNC(saturn_state::stv_intback_peripheral),this),0); /* TODO: is timing correct? */
				m_smpc.OREG[31] = 0x10;
				m_smpc.SF = 0x01; //TODO: set hand-shake flag?
			}
		}
	}

	if (offset == 0x1f) // COMREG
	{
		smpc_comreg_exec(space,data,1);

		// we've processed the command, clear status flag
		if(data != 0x10 && data != 0x02 && data != 0x03 && data != 0x08 && data != 0x09 && data != 0xe && data != 0xf && data != 0x19 && data != 0x1a)
		{
			m_smpc.OREG[31] = data; //read-back command
			m_smpc.SF = 0x00;
		}
		/*TODO:emulate the timing of each command...*/
	}

	if(offset == 0x63)
		m_smpc.SF = data & 1;

	if(offset == 0x75)
	{
		/*
		-xx- ---- PDR1
		---x ---- EEPROM write bit
		---- x--- EEPROM CLOCK line
		---- -x-- EEPROM CS line
		---- --xx A-Bus bank bits
		*/
		m_eeprom->clk_write((data & 0x08) ? ASSERT_LINE : CLEAR_LINE);
		m_eeprom->di_write((data >> 4) & 1);
		m_eeprom->cs_write((data & 0x04) ? ASSERT_LINE : CLEAR_LINE);
		m_stv_multi_bank = data & 3;

		stv_select_game(m_stv_multi_bank);

		m_smpc.PDR1 = (data & 0x60);
	}

	if(offset == 0x77)
	{
		/*
		    -xx- ---- PDR2
		    ---x ---- Enable Sound System (ACTIVE LOW)
		*/
		//popmessage("PDR2 = %02x",m_smpc_ram[0x77]);

		if(LOG_SMPC) printf("SMPC: M68k %s\n",(data & 0x10) ? "off" : "on");
		//machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(saturn_state::smpc_sound_enable),this),(m_smpc_ram[0x77] & 0x10) >> 4);
		m_audiocpu->set_input_line(INPUT_LINE_RESET, (data & 0x10) ? ASSERT_LINE : CLEAR_LINE);
		m_en_68k = ((data & 0x10) >> 4) ^ 1;

		//if(LOG_SMPC) printf("SMPC: ram [0x77] = %02x\n",data);
		m_smpc.PDR2 = (data & 0x60);
	}

	if(offset == 0x7d)
	{
		/*
		---- --x- IOSEL2 direct (1) / control mode (0) port select
		---- ---x IOSEL1 direct (1) / control mode (0) port select
		*/
		m_smpc.IOSEL1 = (data & 1) >> 0;
		m_smpc.IOSEL2 = (data & 2) >> 1;
	}

	if(offset == 0x7f)
	{
		//enable PAD irq & VDP2 external latch for port 1/2
		m_smpc.EXLE1 = (data & 1) >> 0;
		m_smpc.EXLE2 = (data & 2) >> 1;
	}
}

/********************************************
 *
 * Saturn handlers
 *
 *******************************************/

uint8_t saturn_state::smpc_th_control_mode(uint8_t pad_n)
{
	uint8_t res = 0;
	int th = (pad_n == 0) ? ((m_smpc.PDR1 >> 5) & 3) : ((m_smpc.PDR2 >> 5) & 3);

	uint16_t ctrl_read = 0;
	if (m_ctrl1 && pad_n == 0)
		ctrl_read = m_ctrl1->read_direct();
	if (m_ctrl2 && pad_n == 1)
		ctrl_read = m_ctrl2->read_direct();

	if (LOG_SMPC) printf("SMPC: SH-2 TH control mode, returning pad data %d for phase %d\n", pad_n + 1, th);

	switch (th)
	{
		/* TODO: 3D Lemmings bogusly enables TH Control mode, wants this to return the ID, needs HW tests.  */
		case 3:
			res = th << 6;
			res |= 0x14;
			res |= (ctrl_read & 8); // L
			break;
		case 2:
			res = th << 6;
			//  1 C B Right Left Down Up
			//  WHP actually has a very specific code at 0x6015f30, doesn't like bits 0-1 active here ...
			res|= ((ctrl_read >>  4) & 0x30); // C & B
			res|= ((ctrl_read >> 12) & 0xc);
			break;
		case 1:
			res = th << 6;
			res |= 0x10;
			res |= ((ctrl_read >> 4) & 0xf); // R, X, Y, Z
			break;
		case 0:
			res = th << 6;
			//  0 Start A 0 0    Down Up
			res |= ((ctrl_read >>  6) & 0x30); // Start & A
			res |= ((ctrl_read >> 12) & 0x03);
			//  ... and it actually wants bits 2 - 3 active here.
			res |= 0xc;
			break;
	}

	return res;
}

uint8_t saturn_state::smpc_direct_mode(uint8_t pad_n)
{
	int hshake = (pad_n == 0) ? ((m_smpc.PDR1 >> 5) & 3) : ((m_smpc.PDR2 >> 5) & 3);
	const int shift_bit[4] = { 4, 12, 8, 0 };

	uint16_t ctrl_read = 0;
	if (m_ctrl1 && pad_n == 0)
		ctrl_read = m_ctrl1->read_direct();
	if (m_ctrl2 && pad_n == 1)
		ctrl_read = m_ctrl2->read_direct();

	if (LOG_SMPC) logerror("SMPC: SH-2 direct mode, returning data for phase %d\n", hshake);

	return 0x80 | 0x10 | ((ctrl_read >> shift_bit[hshake]) & 0xf);
}

READ8_MEMBER( saturn_state::saturn_SMPC_r )
{
	uint8_t return_data = 0;

	if (!(offset & 1)) // avoid reading to even bytes (TODO: is it 0s or 1s?)
		return 0x00;

	if(offset >= 0x21 && offset <= 0x5f)
		return_data = m_smpc.OREG[(offset-0x21) >> 1];

	if (offset == 0x61)
		return_data = m_smpc.SR;

	if (offset == 0x63)
	{
		//printf("SF %d %d\n",machine().first_screen()->hpos(),machine().first_screen()->vpos());
		return_data = m_smpc.SF;
	}

	if (offset == 0x75 || offset == 0x77)//PDR1/2 read
	{
		if ((m_smpc.IOSEL1 && offset == 0x75) || (m_smpc.IOSEL2 && offset == 0x77))
		{
			uint8_t cur_ddr;

			if (((m_ctrl1 && m_ctrl1->read_id(0) != 0x02) || (m_ctrl2 && m_ctrl2->read_id(0) != 0x02)) && !(space.debugger_access()))
			{
				popmessage("Warning: read with SH-2 direct mode with a non-pad device");
				return 0;
			}

			cur_ddr = (offset == 0x75) ? m_smpc.DDR1 : m_smpc.DDR2;

			switch(cur_ddr & 0x60)
			{
				case 0x00: break; // in diag test
				case 0x40: return_data = smpc_th_control_mode(offset == 0x77); break;
				case 0x60: return_data = smpc_direct_mode(offset == 0x77); break;
				default:
					popmessage("SMPC: unemulated control method %02x, contact MAMEdev",cur_ddr & 0x60);
					return_data = 0;
					break;
			}
		}
	}

	if (LOG_SMPC) logerror ("cpu %s (PC=%08X) SMPC: Read from Byte Offset %02x (%d) Returns %02x\n", space.device().tag(), space.device().safe_pc(), offset, offset>>1, return_data);

	return return_data;
}

WRITE8_MEMBER( saturn_state::saturn_SMPC_w )
{
	if (LOG_SMPC) logerror ("8-bit SMPC Write to Offset %02x (reg %d) with Data %02x\n", offset, offset>>1, data);

	if (!(offset & 1)) // avoid writing to even bytes
		return;

	if(offset >= 1 && offset <= 0xd)
		m_smpc.IREG[offset >> 1] = data;

	if(offset == 1) //IREG0, check if a BREAK / CONTINUE request for INTBACK command
	{
		if(m_smpc.intback_stage)
		{
			if(data & 0x40)
			{
				if(LOG_PAD_CMD) printf("SMPC: BREAK request %02x\n",data);
				m_smpc.SR &= 0x0f;
				m_smpc.intback_stage = 0;
			}
			else if(data & 0x80)
			{
				if(LOG_PAD_CMD) printf("SMPC: CONTINUE request %02x\n",data);
				machine().scheduler().timer_set(attotime::from_usec(700), timer_expired_delegate(FUNC(saturn_state::intback_peripheral),this),0); /* TODO: is timing correct? */
				m_smpc.OREG[31] = 0x10;
				m_smpc.SF = 0x01; //TODO: set hand-shake flag?
			}
		}
	}

	if (offset == 0x1f)
	{
		smpc_comreg_exec(space,data,0);

		// we've processed the command, clear status flag
		if(data != 0x10 && data != 2 && data != 3 && data != 6 && data != 7 && data != 0x08 && data != 0x09 && data != 0x0e && data != 0x0f && data != 0x19 && data != 0x1a)
		{
			m_smpc.OREG[31] = data; //read-back for last command issued
			m_smpc.SF = 0x00; //clear hand-shake flag
		}
		/*TODO:emulate the timing of each command...*/
	}

	if (offset == 0x63)
		m_smpc.SF = data & 1; // hand-shake flag

	if(offset == 0x75)  // PDR1
		m_smpc.PDR1 = data & 0x7f;

	if(offset == 0x77)  // PDR2
		m_smpc.PDR2 = data & 0x7f;

	if(offset == 0x79)
		m_smpc.DDR1 = data & 0x7f;

	if(offset == 0x7b)
		m_smpc.DDR2 = data & 0x7f;

	if(offset == 0x7d)
	{
		m_smpc.IOSEL1 = data & 1;
		m_smpc.IOSEL2 = (data & 2) >> 1;
	}

	if(offset == 0x7f)
	{
		//enable PAD irq & VDP2 external latch for port 1/2
		m_smpc.EXLE1 = (data & 1) >> 0;
		m_smpc.EXLE2 = (data & 2) >> 1;
	}
}