summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/tms6100.cpp
blob: 0728a511e8d096f0360e79f226ea17f154c4b3b2 (plain) (tree)
1
2
3
4
5
6
                       
                                    

                                                                                               
                                                          
 












                                                                                                  


                                                                                                
                

                    
 
                     
 

                                                                     
 





                                                                                                                            
 

 
                                                                                                          
                                                             
 
 
 
 
                                                                                                        
                                                            

 
 
 
                                                   

                                                   
 
                                   
 

                                      
                   
                      






                       

                 


                  
 
                                  
                                   





                                    

                              


                               

 
                                  
 
                                       
                                                                                            

 
 


                                       
 





                                       

 











                                        
                                    
 
                           

 
                                    
 
                            

 
                                             
 
                    
                                    

 
                                        
 
                                  
                                      
         
                         
                 
                                                                      
                                                

                                                                       
 


                                     
 





                                
                                           















                                                      
                         

                                                         
                                 



                                                                             
                                                                                        


                                    


                                                                                
 










                                                                                
                                            
                                                                    
                                 
 

                                                                                
 


                                                                   

                              
 













                                                                                     
                                                                         

                                                                                                     
 

                                                            
                              
 



                                                                                       
                         


                                                                             
                                                                      


                                                                                  
                         
                              
 

                              
         
 
                         
 
// license:BSD-3-Clause
// copyright-holders:hap, Couriersud
/**********************************************************************************************

    Texas Instruments TMS6100 Voice Synthesis Memory (VSM)

    References:
    - TMS 6100 Voice Synthesis Memory Data Manual
    - TMS 6125 Voice Synthesis Memory Data Manual
    - Speak & Spell patent US4189779 for low-level documentation
    - 1982 Mitsubishi Data Book (M58819S section)

    TODO:
    - implement clock pin(CLK) properly, xtal/timer
    - command processing timing is not accurate, on the real chip it will take a few microseconds
    - current implementation does not regard multi-chip configuration and pretends it is 1 chip,
      this will work fine under normal circumstances since CS would be disabled on invalid address
    - implement chip addressing (0-15 mask programmed, see above)
    - M58819S pins SL(PROM expansion input), POC(reset)

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

#include "emu.h"
#include "tms6100.h"


// device definitions

DEFINE_DEVICE_TYPE(TMS6100, tms6100_device, "tms6100", "TMS6100 VSM")
DEFINE_DEVICE_TYPE(M58819,  m58819_device,  "m58819s", "M68819S")


tms6100_device::tms6100_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
	: device_t(mconfig, type, tag, owner, clock)
	, m_rom(*this, DEVICE_SELF)
	, m_reverse_bits(false)
	, m_4bit_mode(false)
{
}

tms6100_device::tms6100_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
	: tms6100_device(mconfig, TMS6100, tag, owner, clock)
{
}


m58819_device::m58819_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
	: tms6100_device(mconfig, M58819, tag, owner, clock)
{
}


//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void tms6100_device::device_start()
{
	m_rommask = m_rom.bytes() - 1;

	// zerofill
	m_address = 0;
	m_sa = 0;
	m_count = 0;
	m_prev_cmd = 0;
	m_prev_m = 0;

	m_add = 0;
	m_data = 0;
	m_m0 = 0;
	m_m1 = 0;
	m_cs = 1;
	m_clk = 0;
	m_rck = 0;

	// register for savestates
	save_item(NAME(m_address));
	save_item(NAME(m_sa));
	save_item(NAME(m_count));
	save_item(NAME(m_prev_cmd));
	save_item(NAME(m_prev_m));
	save_item(NAME(m_add));
	save_item(NAME(m_data));
	save_item(NAME(m_m0));
	save_item(NAME(m_m1));
	save_item(NAME(m_cs));
	save_item(NAME(m_clk));
	save_item(NAME(m_rck));
}

void m58819_device::device_start()
{
	tms6100_device::device_start();
	m_reverse_bits = true; // m58819 'vsm-emulator' chip expects ROM bit order backwards
}


// external i/o

WRITE_LINE_MEMBER(tms6100_device::m0_w)
{
	m_m0 = (state) ? 1 : 0;
}

WRITE_LINE_MEMBER(tms6100_device::m1_w)
{
	m_m1 = (state) ? 1 : 0;
}

WRITE_LINE_MEMBER(tms6100_device::cs_w)
{
	// chip select pin
	m_cs = (state) ? 1 : 0;
}

WRITE_LINE_MEMBER(tms6100_device::rck_w)
{
	// gate/mask for clk
	m_rck = (state) ? 1 : 0;
}

WRITE8_MEMBER(tms6100_device::add_w)
{
	m_add = data & 0xf;
}

READ8_MEMBER(tms6100_device::data_r)
{
	return m_data & 0xf;
}

READ_LINE_MEMBER(tms6100_device::data_line_r)
{
	// DATA/ADD8
	return (m_data & 8) ? 1 : 0;
}

WRITE_LINE_MEMBER(tms6100_device::clk_w)
{
	// process on falling edge
	if (m_clk && !m_rck && !state)
	{
		if (m_cs)
		{
			// new command enabled on rising edge of m0/m1
			u8 m = m_m1 << 1 | m_m0;
			if ((m & ~m_prev_m & 1) || (m & ~m_prev_m & 2))
				handle_command(m);

			m_prev_m = m;
		}
	}

	m_clk = (state) ? 1 : 0;
}


// m0/m1 commands

void tms6100_device::handle_command(u8 cmd)
{
	enum
	{
		M_NOP = 0, M_TB, M_LA, M_RB
	};

	switch (cmd)
	{
		// TB: transfer bit (read)
		case M_TB:
			if (m_prev_cmd == M_LA)
			{
				// dummy read after LA
				m_count = 0;
			}
			else
			{
				// load new data from rom
				if (m_count == 0)
				{
					m_sa = m_rom[m_address & m_rommask];

					// M58819S reads serial data reversed
					if (m_reverse_bits)
						m_sa = bitswap<8>(m_sa,0,1,2,3,4,5,6,7);
				}
				else
				{
					// or shift(rotate) right
					m_sa = (m_sa >> 1) | (m_sa << 7 & 0x80);
				}

				// output to DATA pin(s)
				if (!m_4bit_mode)
				{
					// 1-bit mode: SA0 to ADD8/DATA
					m_data = m_sa << 3 & 8;
				}
				else
				{
					// 4-bit mode: SA0-3 or SA3-6(!) to DATA
					if (m_count & 1)
						m_data = m_sa >> 3 & 0xf;
					else
						m_data = m_sa & 0xf;
				}

				// 8 bits in 1-bit mode, otherwise 2 nybbles
				m_count = (m_count + 1) & (m_4bit_mode ? 1 : 7);

				// TB8
				if (m_count == 0)
					m_address++; // CS bits too
			}
			break;

		// LA: load address
		case M_LA:
			if (m_prev_cmd == M_TB)
			{
				// start LA after TB
				m_address = (m_address & ~0xf) | m_add;
				m_count = 0;
			}
			else if (m_prev_cmd == M_LA)
			{
				// load consecutive address bits (including CS bits)
				// the 8-step counter PLA is shared between LA and TB
				if (m_count < 4)
				{
					const u8 shift = 4 * (m_count+1);
					m_address = (m_address & ~(0xf << shift)) | (m_add << shift);
				}

				m_count = (m_count + 1) & 7;
			}
			break;

		// RB: read and branch
		case M_RB:
			// process RB after LA or TB8
			if (m_prev_cmd == M_LA || (m_prev_cmd == M_TB && m_count == 0))
			{
				m_count = 0;

				// load new address bits (14 bits on TMS6100)
				u16 rb = m_rom[m_address & m_rommask];
				m_address++;
				rb |= (m_rom[m_address & m_rommask] << 8);
				m_address = (m_address & ~0x3fff) | (rb & 0x3fff);
			}
			break;

		default:
			break;
	}

	m_prev_cmd = cmd;
}