summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/nmc9306.cpp
blob: 2001f58e78d0c0578eb101994acb297b0e4339d0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                               



                                                                       



                                                                       
 


                     





                                                                            






                   


                                                  




                     


                                              
                                             





                       
                    


                      
                        
                       

                    




                                                                            


                                                                            
                         
                                                                        
 



                                                   
                                                   








                                                   
                                                          


                   
                                          

























                                                                            












                                                                                                                 









                                                   

                                                  




















                                                   

                                      







                                                   
                                                        
 

                                                                          







                                                   
                                                          
 

                                                                           






                                                   
                                    
 














                                                                      
                                                                                              









                                                                               
                                                                                              












                                                                                          
                                 
                                      





                                                                             
                                 
                                      







                                             







                                                   
                                    
 




                                      
                     
 

                                                                                          
 


                        
                                               
 
                          

                                             








                                                



                                                
 
                           
                                                      
 

                                  

                                 
                         
 





                                                
 
                           
                                                      
 

                                  

                                 
                         
 







                                                         
                                                              


                                                             
 
                                          

                                                                      
                                              
 
                                          

                                                                      


                                              
                                                              






                                                             
                                                                             

                                                        
 
                                  


                                                                                 
                                      
 
                                   

                                                                             

                                      
 


                                   
 
                           
                                                      
 

                               
 
                         
 

                                 
                                              

                      
 

                             
 



                                                        
 
                            

                                       


                                                       
                         
 












                                                   
                                    








                                                   
                          


                    
// license:BSD-3-Clause
// copyright-holders:Curt Coder
/**********************************************************************

    National Semiconductor NMC9306 256-Bit Serial EEPROM emulation

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

#include "emu.h"
#include "nmc9306.h"

//#define VERBOSE 1
#include "logmacro.h"



//**************************************************************************
//  MACROS / CONSTANTS
//**************************************************************************

#define RAM_SIZE 32


// instructions
enum
{
	OTHER = 0,
	WRITE,          // write register A3A2A1A0
	READ,           // read register  A3A2A1A0
	ERASE           // erase register A3A2A1A0
};

// other instructions
enum
{
	EWDS = 0,       // erase/write disable
	WRAL,           // write all registers
	ERAL,           // erase all registers
	EWEN            // erase/write enable
};

// states
enum
{
	STATE_IDLE = 0,
	STATE_START,
	STATE_COMMAND,
	STATE_ADDRESS,
	STATE_DATA_IN,
	STATE_DUMMY_OUT,
	STATE_DATA_OUT,
	STATE_ERASE,
	STATE_WRITE
};



//**************************************************************************
//  INLINE HELPERS
//**************************************************************************

// device type definition
DEFINE_DEVICE_TYPE(NMC9306, nmc9306_device, "nmc9306", "NMC9306 EEPROM")

//-------------------------------------------------
//  nmc9306_device - constructor
//-------------------------------------------------

inline uint16_t nmc9306_device::read(offs_t offset)
{
	return m_register[offset];
}


//-------------------------------------------------
//  nmc9306_device - constructor
//-------------------------------------------------

inline void nmc9306_device::write(offs_t offset, u16 data)
{
	if (m_ewen)
	{
		m_register[offset] = data;
	}
}


//-------------------------------------------------
//  nmc9306_device - constructor
//-------------------------------------------------

inline void nmc9306_device::erase(offs_t offset)
{
	if (m_ewen)
	{
		m_register[offset] = 0xffff;
	}
}



//**************************************************************************
//  LIVE DEVICE
//**************************************************************************

//-------------------------------------------------
//  nmc9306_device - constructor
//-------------------------------------------------

nmc9306_device::nmc9306_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, NMC9306, tag, owner, clock),
	device_nvram_interface(mconfig, *this),
	m_bits(0),
	m_state(STATE_IDLE),
	m_command(0),
	m_address(0),
	m_data(0),
	m_ewen(false),
	m_cs(0),
	m_sk(0),
	m_do(0),
	m_di(0)
{
}


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

void nmc9306_device::device_start()
{
	memset(m_register, 0, sizeof(m_register));

	// state saving
	save_item(NAME(m_bits));
	save_item(NAME(m_state));
	save_item(NAME(m_command));
	save_item(NAME(m_address));
	save_item(NAME(m_data));
	save_item(NAME(m_ewen));
	save_item(NAME(m_cs));
	save_item(NAME(m_sk));
	save_item(NAME(m_do));
	save_item(NAME(m_di));
}


//-------------------------------------------------
//  nvram_default - called to initialize NVRAM to
//  its default state
//-------------------------------------------------

void nmc9306_device::nvram_default()
{
	for (auto & elem : m_register)
		elem = 0xffff;
}


//-------------------------------------------------
//  nvram_read - called to read NVRAM from the
//  .nv file
//-------------------------------------------------

bool nmc9306_device::nvram_read(util::read_stream &file)
{
	auto const [err, actual] = util::read(file, m_register, RAM_SIZE);
	return !err && (actual == RAM_SIZE);
}


//-------------------------------------------------
//  nvram_write - called to write NVRAM to the
//  .nv file
//-------------------------------------------------

bool nmc9306_device::nvram_write(util::write_stream &file)
{
	auto const [err, actual] = util::write(file, m_register, RAM_SIZE);
	return !err;
}


//-------------------------------------------------
//  cs_w - chip select input
//-------------------------------------------------

void nmc9306_device::cs_w(int state)
{
	if (m_cs != state)
	{
		LOG("NMC9306 CS %u\n", state);

		if (m_cs && !state)
		{
			switch ((m_command >> 2) & 0x03)
			{
			case OTHER:
				switch (m_command & 0x03)
				{
				case WRAL:
					if (m_state == STATE_WRITE)
					{
						LOG("NMC9306 WRAL\n");
						for (int address = 0; address < 16; address++)
						{
							write(address, m_data);
						}
					}
					break;

				case ERAL:
					if (m_state == STATE_ERASE)
					{
						LOG("NMC9306 ERAL\n");
						for (int address = 0; address < 16; address++)
						{
							erase(address);
						}
					}
					break;
				}
				break;

			case WRITE:
				if (m_state == STATE_WRITE)
				{
					LOG("NMC9306 WRITE %u:%04x\n", m_address, m_data);
					write(m_address, m_data);
				}
				break;

			case ERASE:
				if (m_state == STATE_ERASE)
				{
					LOG("NMC9306 ERASE %u\n", m_address);
					erase(m_address);
				}
				break;
			}

			m_state = STATE_IDLE;
			m_bits = 0;
			m_do = 0;
		}
	}

	m_cs = state;
}


//-------------------------------------------------
//  ck_w - serial clock input
//-------------------------------------------------

void nmc9306_device::sk_w(int state)
{
	if (!m_cs) return;
	if (m_sk == state) return;

	LOG("NMC9306 SK %u\n", state);

	m_sk = state;

	if (m_sk && ((m_state == STATE_DUMMY_OUT) || (m_state == STATE_DATA_OUT))) return;
	if (!m_sk && (m_state != STATE_DUMMY_OUT) && (m_state != STATE_DATA_OUT)) return;

	switch (m_state)
	{
	case STATE_IDLE:
		LOG("NMC9306 Idle %u\n", m_di);

		if (!m_di)
		{
			// start bit received
			m_state = STATE_START;
		}
		break;

	case STATE_START:
		LOG("NMC9306 Start %u\n", m_di);

		if (m_di)
		{
			m_state = STATE_COMMAND;
			m_bits = 0;
		}
		break;

	case STATE_COMMAND:
		LOG("NMC9306 Command Bit %u\n", m_di);

		m_command <<= 1;
		m_command |= m_di;
		m_command &= 0xf;

		m_bits++;

		if (m_bits == 4)
		{
			m_state = STATE_ADDRESS;
			m_bits = 0;
		}
		break;

	case STATE_ADDRESS:
		LOG("NMC9306 Address Bit %u\n", m_di);

		m_address <<= 1;
		m_address |= m_di;
		m_address &= 0xf;

		m_bits++;

		if (m_bits == 4)
		{
			switch ((m_command >> 2) & 0x03)
			{
			case OTHER:
				switch (m_command & 0x03)
				{
				case EWDS:
					LOG("NMC9306 EWDS\n");
					m_ewen = false;
					m_state = STATE_IDLE;
					break;

				case WRAL:
					LOG("NMC9306 Command WRAL\n");
					m_state = STATE_DATA_IN;
					break;

				case ERAL:
					LOG("NMC9306 Command ERAL\n");
					m_state = ERASE;
					break;

				case EWEN:
					LOG("NMC9306 EWEN\n");
					m_ewen = true;
					m_state = STATE_IDLE;
					break;
				}
				break;

			case WRITE:
				LOG("NMC9306 Command WRITE %u\n", m_address);
				m_state = STATE_DATA_IN;
				break;

			case READ:
				m_data = read(m_address);
				LOG("NMC9306 READ %u:%04x\n", m_address, m_data);
				m_state = STATE_DUMMY_OUT;
				break;

			case ERASE:
				LOG("NMC9306 Command ERASE %u\n", m_address);
				m_state = ERASE;
				break;
			}

			m_bits = 0;
		}
		break;

	case STATE_DATA_IN:
		LOG("NMC9306 Data Bit IN %u\n", m_di);

		m_data <<= 1;
		m_data |= m_di;

		m_bits++;

		if (m_bits == 16)
		{
			m_state = STATE_WRITE;
		}
		break;

	case STATE_DUMMY_OUT:
		m_do = 0;

		LOG("NMC9306 Dummy Bit OUT %u\n", m_do);

		m_state = STATE_DATA_OUT;
		break;

	case STATE_DATA_OUT:
		m_do = BIT(m_data, 15);
		m_data <<= 1;

		LOG("NMC9306 Data Bit OUT %u\n", m_do);

		m_bits++;

		if (m_bits == 16)
		{
			m_state = STATE_IDLE;
		}
		break;
	}
}


//-------------------------------------------------
//  di_w - serial data input
//-------------------------------------------------

void nmc9306_device::di_w(int state)
{
	m_di = state;
}


//-------------------------------------------------
//  do_r - serial data output
//-------------------------------------------------

int nmc9306_device::do_r()
{
	return m_do;
}