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









                                                                            
                     
































































                                                                                                                                           
                                                                                     













                                                   


                                                                  

                                                      

                                   
                                                                         









                                                                                 
                                                         
 
                                                          
 

                                                                                      
                             
 

                                                                  

                    






                                                   
                                                           
 
                                                          
 

                                                                  
 

                                                                                       


























































































                                                                                                                                                  
                                                                                                                 















                                                                                                         
                                           









                                                                                            
                                           









                                                                                            
                                                        
 
                          
 
// license:BSD-3-Clause
// copyright-holders:smf, R. Belmont
/***************************************************************************
    ATMEL AT28C64B

    64K ( 8K x 8 ) Parallel EEPROM with flash-like in-band signalling

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

#include "emu.h"
#include "at28c64b.h"

static constexpr int AT28C64B_DATA_BYTES = 0x10000;
static constexpr int AT28C64B_ID_BYTES = 0x40;
static constexpr int AT28C64B_TOTAL_BYTES = AT28C64B_DATA_BYTES + AT28C64B_ID_BYTES;

static constexpr int AT28C64B_ID_OFFSET = 0x1fc0;
static constexpr int AT28C64B_SECTOR_SIZE = 0x40;


//**************************************************************************
//  GLOBAL VARIABLES
//**************************************************************************

void at28c64b_device::at28c64b_map8(address_map &map)
{
	map(0x00000, 0x1003f).ram();
}



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

// device type definition
DEFINE_DEVICE_TYPE(AT28C64B, at28c64b_device, "at28c64b", "AT28C64B 8Kx8 EEPROM")

//-------------------------------------------------
//  at28c64b_device - constructor
//-------------------------------------------------

at28c64b_device::at28c64b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, AT28C64B, tag, owner, clock),
		device_memory_interface(mconfig, *this),
		device_nvram_interface(mconfig, *this),
		m_space_config("at28c64b", ENDIANNESS_BIG, 8,  17, 0, address_map_constructor(FUNC(at28c64b_device::at28c64b_map8), this)),
		m_a9_12v(0),
		m_oe_12v(0),
		m_last_write(-1),
		m_state(0),
		m_bytes_in_sector(0),
		m_default_data(*this, DEVICE_SELF)
{
}


//-------------------------------------------------
//  memory_space_config - return a description of
//  any address spaces owned by this device
//-------------------------------------------------

device_memory_interface::space_config_vector at28c64b_device::memory_space_config() const
{
	return space_config_vector {
		std::make_pair(0, &m_space_config)
	};
}


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

void at28c64b_device::device_start()
{
	m_write_timer = timer_alloc( FUNC( at28c64b_device::write_complete ), this );

	save_item( NAME(m_a9_12v) );
	save_item( NAME(m_oe_12v) );
	save_item( NAME(m_last_write) );
}


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

void at28c64b_device::nvram_default()
{
	uint16_t const default_value = 0xff;
	for (offs_t offs = 0; offs < AT28C64B_TOTAL_BYTES; offs++)
		space(AS_PROGRAM).write_byte(offs, default_value);

	/* populate from a memory region if present */
	if (m_default_data.found())
	{
		for (offs_t offs = 0; offs < AT28C64B_DATA_BYTES; offs++)
			space(AS_PROGRAM).write_byte(offs, m_default_data[offs]);
	}
}


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

bool at28c64b_device::nvram_read(util::read_stream &file)
{
	std::vector<uint8_t> buffer(AT28C64B_TOTAL_BYTES);

	auto const [err, actual] = util::read(file, &buffer[0], AT28C64B_TOTAL_BYTES);
	if (err || (actual != AT28C64B_TOTAL_BYTES))
		return false;

	for (offs_t offs = 0; offs < AT28C64B_TOTAL_BYTES; offs++)
		space(AS_PROGRAM).write_byte(offs, buffer[offs]);

	return true;
}

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

bool at28c64b_device::nvram_write(util::write_stream &file)
{
	std::vector<uint8_t> buffer(AT28C64B_TOTAL_BYTES);

	for (offs_t offs = 0; offs < AT28C64B_TOTAL_BYTES; offs++)
		buffer[offs] = space(AS_PROGRAM).read_byte(offs);

	auto const [err, actual] = util::write(file, &buffer[0], AT28C64B_TOTAL_BYTES);
	return !err;
}



//**************************************************************************
//  READ/WRITE HANDLERS
//**************************************************************************

void at28c64b_device::write(offs_t offset, uint8_t data)
{
	logerror("%s: AT28C64B: write( %04x, %02x ) state %d last_write %d\n", machine().describe_context(), offset, data, m_state, m_last_write);

	if (m_state == STATE_SECTOR_WRITE)
	{
		logerror("SECTOR WRITE: %02x @ %x\n", data, offset);
		this->space(AS_PROGRAM).write_byte(offset, data);
		m_last_write = data;
		m_write_timer->adjust(attotime::from_usec(10));
		m_bytes_in_sector--;
		if (m_bytes_in_sector == 0)
		{
			m_state = STATE_WRITE_PROTECT;
		}
		return;
	}

	if( m_last_write >= 0 )
	{
//      logerror( "%s: AT28C64B: write( %04x, %02x ) busy\n", machine().describe_context(), offset, data );
	}
	else if( m_oe_12v )
	{
//      logerror( "%s: AT28C64B: write( %04x, %02x ) erase\n", machine().describe_context(), offset, data );
		if( m_last_write < 0 )
		{
			for( offs_t offs = 0; offs < AT28C64B_TOTAL_BYTES; offs++ )
			{
				this->space(AS_PROGRAM).write_byte( offs, 0xff );
			}

			m_last_write = 0xff;
			m_write_timer->adjust( attotime::from_usec( 10 ) );
		}
	}
	else
	{
		if ((offset == 0x1555) && (data == 0xaa))
		{
			m_state = STATE_ID_1;
			return;
		}

		if ((m_state == STATE_ID_1) && (offset == 0xaaa) && (data == 0x55))
		{
			m_state = STATE_ID_2;
			return;
		}

		if ((m_state == STATE_ID_2) && (offset == 0x1555) && (data == 0xa0))
		{
			m_state = STATE_SECTOR_WRITE;
			m_bytes_in_sector = AT28C64B_SECTOR_SIZE;
			return;
		}

		if (m_state == STATE_WRITE_PROTECT)
		{
			logerror("%s: write %02x to %x while write protected\n", machine().describe_context(), data, offset);
			return;
		}

		if ((m_a9_12v) && (offset >= AT28C64B_ID_OFFSET) && (offset < (AT28C64B_ID_OFFSET + AT28C64B_ID_BYTES)))
		{
			offset += AT28C64B_ID_BYTES;
		}

		if( m_last_write < 0 && this->space(AS_PROGRAM).read_byte( offset ) != data )
		{
			this->space(AS_PROGRAM).write_byte( offset, data );
			m_last_write = data;
			m_write_timer->adjust( attotime::from_usec( 10 ) );
		}
	}
}


uint8_t at28c64b_device::read(offs_t offset)
{
	if( m_last_write >= 0 )
	{
		uint8_t data = m_last_write ^ 0x80;
//      logerror( "%s: AT28C64B: read( %04x ) write status %02x\n", machine().describe_context(), offset, data );
		return data;
	}
	else
	{
		if( m_a9_12v && offset >= AT28C64B_ID_OFFSET )
		{
			offset += AT28C64B_ID_BYTES;
		}

		uint8_t data = this->space(AS_PROGRAM).read_byte( offset );
//      logerror( "%s: AT28C64B: read( %04x ) data %02x\n", machine().describe_context(), offset, data );
		return data;
	}
}


void at28c64b_device::set_a9_12v(int state)
{
	state &= 1;
	if( m_a9_12v != state )
	{
//      logerror( "%s: AT28C64B: set_a9_12v( %d )\n", machine().describe_context(), state );
		m_a9_12v = state;
	}
}


void at28c64b_device::set_oe_12v(int state)
{
	state &= 1;
	if( m_oe_12v != state )
	{
//      logerror( "%s: AT28C64B: set_oe_12v( %d )\n", machine().describe_context(), state );
		m_oe_12v = state;
	}
}


TIMER_CALLBACK_MEMBER( at28c64b_device::write_complete )
{
	m_last_write = -1;
}