summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/x76f041.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/x76f041.cpp')
-rw-r--r--src/devices/machine/x76f041.cpp246
1 files changed, 234 insertions, 12 deletions
diff --git a/src/devices/machine/x76f041.cpp b/src/devices/machine/x76f041.cpp
index 03fb5b65bf9..06b831eeda6 100644
--- a/src/devices/machine/x76f041.cpp
+++ b/src/devices/machine/x76f041.cpp
@@ -48,13 +48,15 @@ x76f041_device::x76f041_device( const machine_config &mconfig, const char *tag,
m_bit( 0 ),
m_byte( 0 ),
m_command( 0 ),
- m_address( 0 )
+ m_address( 0 ),
+ m_is_password_accepted ( false )
{
}
void x76f041_device::device_start()
{
- memset( m_write_buffer, 0, sizeof( m_write_buffer ) );
+ std::fill( std::begin( m_write_buffer ), std::end( m_write_buffer ), 0 );
+ std::fill( std::begin( m_password_temp ), std::end( m_password_temp ), 0 );
save_item( NAME( m_cs ) );
save_item( NAME( m_rst ) );
@@ -67,6 +69,7 @@ void x76f041_device::device_start()
save_item( NAME( m_byte ) );
save_item( NAME( m_command ) );
save_item( NAME( m_address ) );
+ save_item( NAME( m_is_password_accepted ) );
save_item( NAME( m_write_buffer ) );
save_item( NAME( m_response_to_reset ) );
save_item( NAME( m_write_password ) );
@@ -74,6 +77,26 @@ void x76f041_device::device_start()
save_item( NAME( m_configuration_password ) );
save_item( NAME( m_configuration_registers ) );
save_item( NAME( m_data ) );
+ save_item( NAME( m_password_temp ) );
+}
+
+void x76f041_device::device_reset()
+{
+ std::fill( std::begin( m_write_buffer ), std::end( m_write_buffer ), 0 );
+ std::fill( std::begin( m_password_temp ), std::end( m_password_temp ), 0 );
+
+ m_cs = 0;
+ m_rst = 0;
+ m_scl = 0;
+ m_sdaw = 0;
+ m_sdar = 0;
+ m_state = STATE_STOP;
+ m_shift = 0;
+ m_bit = 0;
+ m_byte = 0;
+ m_command = 0;
+ m_address = 0;
+ m_is_password_accepted = false;
}
WRITE_LINE_MEMBER( x76f041_device::write_cs )
@@ -128,6 +151,15 @@ uint8_t *x76f041_device::password()
case COMMAND_READ:
return m_read_password;
+ case COMMAND_CONFIGURATION:
+ if( m_address == CONFIGURATION_PROGRAM_WRITE_PASSWORD )
+ return m_write_password;
+
+ if( m_address == CONFIGURATION_PROGRAM_READ_PASSWORD )
+ return m_read_password;
+
+ return m_configuration_password;
+
default:
return m_configuration_password;
}
@@ -135,6 +167,9 @@ uint8_t *x76f041_device::password()
void x76f041_device::password_ok()
{
+ if( m_configuration_registers[ CONFIG_CR ] & CR_RETRY_COUNTER_RESET_BIT )
+ m_configuration_registers[ CONFIG_RC ] = 0;
+
switch( m_command & 0xe0 )
{
case COMMAND_WRITE:
@@ -144,7 +179,7 @@ void x76f041_device::password_ok()
m_state = STATE_READ_DATA;
break;
case COMMAND_WRITE_USE_CONFIGURATION_PASSWORD:
- m_state = STATE_WRITE_DATA;
+ m_state = STATE_CONFIGURATION_WRITE_DATA;
break;
case COMMAND_READ_USE_CONFIGURATION_PASSWORD:
m_state = STATE_READ_DATA;
@@ -153,14 +188,22 @@ void x76f041_device::password_ok()
switch( m_address )
{
case CONFIGURATION_PROGRAM_WRITE_PASSWORD:
+ m_state = STATE_PROGRAM_WRITE_PASSWORD;
+ m_byte = 0;
break;
case CONFIGURATION_PROGRAM_READ_PASSWORD:
+ m_state = STATE_PROGRAM_READ_PASSWORD;
+ m_byte = 0;
break;
case CONFIGURATION_PROGRAM_CONFIGURATION_PASSWORD:
+ m_state = STATE_PROGRAM_CONFIGURATION_PASSWORD;
+ m_byte = 0;
break;
case CONFIGURATION_RESET_WRITE_PASSWORD:
+ m_state = STATE_RESET_WRITE_PASSWORD;
break;
case CONFIGURATION_RESET_READ_PASSWORD:
+ m_state = STATE_RESET_READ_PASSWORD;
break;
case CONFIGURATION_PROGRAM_CONFIGURATION_REGISTERS:
m_state = STATE_WRITE_CONFIGURATION_REGISTERS;
@@ -171,8 +214,10 @@ void x76f041_device::password_ok()
m_byte = 0;
break;
case CONFIGURATION_MASS_PROGRAM:
+ m_state = STATE_MASS_PROGRAM;
break;
case CONFIGURATION_MASS_ERASE:
+ m_state = STATE_MASS_ERASE;
break;
default:
break;
@@ -182,21 +227,56 @@ void x76f041_device::password_ok()
void x76f041_device::load_address()
{
- /* todo: handle other bcr bits */
- int bcr;
-
m_address = m_shift;
verboselog( 1, "-> address: %02x\n", m_address );
- if( ( m_command & 1 ) == 0 )
+ if( ( m_configuration_registers[ CONFIG_CR ] & CR_RETRY_COUNTER_ENABLE_BIT ) != 0 &&
+ m_configuration_registers[ CONFIG_RR ] == m_configuration_registers[ CONFIG_RC ] &&
+ ( m_configuration_registers[ CONFIG_CR ] & CR_UNAUTHORIZED_ACCESS_BITS ) == 0x80 )
{
- bcr = m_configuration_registers[ CONFIG_BCR1 ];
+ // No commands are allowed
+ verboselog( 1, "unauthorized access rejected\n" );
+ m_state = STATE_STOP;
+ m_sdar = 1;
+ m_byte = 0;
+ return;
}
- else
+
+ if( ( m_command & 0xe0 ) == COMMAND_CONFIGURATION )
{
- bcr = m_configuration_registers[ CONFIG_BCR2 ];
+ // Configuration commands can be used regardless of array control register bits
+ if( m_address == CONFIGURATION_RESET_WRITE_PASSWORD ||
+ m_address == CONFIGURATION_RESET_READ_PASSWORD ||
+ m_address == CONFIGURATION_MASS_PROGRAM ||
+ m_address == CONFIGURATION_MASS_ERASE )
+ {
+ verboselog( 1, "password not required\n" );
+ password_ok();
+ }
+ else
+ {
+ verboselog( 1, "send password\n" );
+ m_state = STATE_LOAD_PASSWORD;
+ m_byte = 0;
+ }
+
+ return;
+ }
+
+ if( ( m_configuration_registers[ CONFIG_CR ] & CR_RETRY_COUNTER_ENABLE_BIT ) != 0 &&
+ m_configuration_registers[ CONFIG_RR ] == m_configuration_registers[ CONFIG_RC ] &&
+ ( m_configuration_registers[ CONFIG_CR ] & CR_UNAUTHORIZED_ACCESS_BITS ) != 0x80 )
+ {
+ // Only configuration commands are allowed
+ verboselog( 1, "unauthorized access rejected\n" );
+ m_state = STATE_STOP;
+ m_sdar = 1;
+ m_byte = 0;
+ return;
}
+
+ int bcr = m_configuration_registers[ ( m_command & 1 ) ? CONFIG_BCR2 : CONFIG_BCR1 ];
if( ( m_address & 0x80 ) != 0 )
{
bcr >>= 4;
@@ -208,7 +288,8 @@ void x76f041_device::load_address()
/* todo: find out when this is really checked. */
verboselog( 1, "command not allowed\n" );
m_state = STATE_STOP;
- m_sdar = 0;
+ m_sdar = 1;
+ m_byte = 0;
}
else if( ( ( m_command & 0xe0 ) == COMMAND_WRITE && ( bcr & BCR_X ) == 0 ) ||
( ( m_command & 0xe0 ) == COMMAND_READ && ( bcr & BCR_Y ) == 0 ) )
@@ -272,7 +353,15 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
case STATE_LOAD_PASSWORD:
case STATE_VERIFY_PASSWORD:
case STATE_WRITE_DATA:
+ case STATE_CONFIGURATION_WRITE_DATA:
case STATE_WRITE_CONFIGURATION_REGISTERS:
+ case STATE_PROGRAM_WRITE_PASSWORD:
+ case STATE_PROGRAM_READ_PASSWORD:
+ case STATE_PROGRAM_CONFIGURATION_PASSWORD:
+ case STATE_RESET_WRITE_PASSWORD:
+ case STATE_RESET_READ_PASSWORD:
+ case STATE_MASS_PROGRAM:
+ case STATE_MASS_ERASE:
if( m_scl == 0 && state != 0 )
{
if( m_bit < 8 )
@@ -311,6 +400,16 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
if( m_byte == sizeof( m_write_buffer ) )
{
m_state = STATE_VERIFY_PASSWORD;
+
+ // Perform the password acceptance check before verify password because
+ // password verify ack is spammed and will quickly overflow the
+ // retry counter.
+ m_is_password_accepted = memcmp( password(), m_write_buffer, sizeof( m_write_buffer ) ) == 0;
+ if( !m_is_password_accepted )
+ {
+ if( m_configuration_registers[ CONFIG_CR ] & CR_RETRY_COUNTER_ENABLE_BIT )
+ m_configuration_registers[ CONFIG_RC ]++;
+ }
}
break;
@@ -321,7 +420,7 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
if( m_shift == 0xc0 )
{
/* todo: this should take 10ms before it returns ok. */
- if( memcmp( password(), m_write_buffer, sizeof( m_write_buffer ) ) == 0 )
+ if( m_is_password_accepted )
{
password_ok();
}
@@ -338,6 +437,36 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
if( m_byte == sizeof( m_write_buffer ) )
{
+ int bcr = m_configuration_registers[ ( m_command & 1 ) ? CONFIG_BCR2 : CONFIG_BCR1 ];
+ if( ( m_address & 0x80 ) != 0 )
+ {
+ bcr >>= 4;
+ }
+
+ if( ( bcr & ( BCR_Z | BCR_T ) ) == BCR_T )
+ {
+ // Bits in the data can only be set, not cleared, when in program only mode
+ bool is_unauthorized_write = false;
+
+ for( m_byte = 0; m_byte < sizeof( m_write_buffer ); m_byte++ )
+ {
+ int offset = data_offset();
+ if( m_write_buffer[ m_byte ] < m_data[ offset ] )
+ {
+ verboselog( 1, "tried to unset bits while in program only mode\n" );
+ is_unauthorized_write = true;
+ break;
+ }
+ }
+
+ if( is_unauthorized_write )
+ {
+ m_sdar = 1;
+ m_byte = 0;
+ break;
+ }
+ }
+
for( m_byte = 0; m_byte < sizeof( m_write_buffer ); m_byte++ )
{
int offset = data_offset();
@@ -350,6 +479,15 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
}
break;
+
+ case STATE_CONFIGURATION_WRITE_DATA:
+ // Unlike normal writes, configuration writes aren't required to be exactly 8 bytes
+ // TODO: Store data in a temporary buffer until the proper end of the command before writing
+ verboselog( 2, "-> data: %02x\n", m_shift );
+ m_data[ data_offset() ] = m_shift;
+ m_byte++;
+ break;
+
case STATE_WRITE_CONFIGURATION_REGISTERS:
verboselog( 1, "-> configuration register[ %d ]: %02x\n", m_byte, m_shift );
/* todo: write after all bytes received? */
@@ -360,6 +498,90 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
m_byte = 0;
}
break;
+
+ case STATE_PROGRAM_WRITE_PASSWORD:
+ verboselog( 1, "-> program write password[ %d ]: %02x\n", m_byte, m_shift );
+ m_password_temp[ m_byte++ ] = m_shift;
+
+ if( m_byte == sizeof( m_password_temp ) )
+ {
+ // Read in the password twice and if the two copies match then write it to the password field
+ if( memcmp( &m_password_temp[ 0 ], &m_password_temp[ 8 ], sizeof( m_write_password ) ) == 0 )
+ {
+ std::copy_n( std::begin( m_password_temp ), sizeof( m_write_password ), std::begin ( m_write_password ) );
+ }
+ else {
+ m_sdar = 1;
+ }
+
+ std::fill( std::begin( m_password_temp ), std::end( m_password_temp ), 0 );
+
+ m_byte = 0;
+ }
+ break;
+
+ case STATE_PROGRAM_READ_PASSWORD:
+ verboselog( 1, "-> program read password[ %d ]: %02x\n", m_byte, m_shift );
+ m_password_temp[ m_byte++ ] = m_shift;
+
+ if( m_byte == sizeof( m_password_temp ) )
+ {
+ if( memcmp( &m_password_temp[ 0 ], &m_password_temp[ 8 ], sizeof( m_read_password ) ) == 0 )
+ {
+ std::copy_n( std::begin( m_password_temp ), sizeof( m_read_password ), std::begin ( m_read_password ) );
+ }
+ else {
+ m_sdar = 1;
+ }
+
+ std::fill( std::begin( m_password_temp ), std::end( m_password_temp ), 0 );
+
+ m_byte = 0;
+ }
+ break;
+
+ case STATE_PROGRAM_CONFIGURATION_PASSWORD:
+ verboselog( 1, "-> program configuration password[ %d ]: %02x\n", m_byte, m_shift );
+ m_password_temp[ m_byte++ ] = m_shift;
+
+ if( m_byte == sizeof( m_password_temp ) )
+ {
+ if( memcmp( &m_password_temp[ 0 ], &m_password_temp[ 8 ], sizeof( m_configuration_password ) ) == 0 )
+ {
+ std::copy_n( std::begin( m_password_temp ), sizeof( m_configuration_password ), std::begin ( m_configuration_password ) );
+ }
+ else {
+ m_sdar = 1;
+ }
+
+ std::fill( std::begin( m_password_temp ), std::end( m_password_temp ), 0 );
+
+ m_byte = 0;
+ }
+ break;
+
+ case STATE_RESET_WRITE_PASSWORD:
+ verboselog( 1, "-> reset write password\n" );
+ std::fill( std::begin( m_write_password ), std::end( m_write_password ), 0 );
+ break;
+
+ case STATE_RESET_READ_PASSWORD:
+ verboselog( 1, "-> reset read password\n" );
+ std::fill( std::begin( m_read_password ), std::end( m_read_password ), 0 );
+ break;
+
+ case STATE_MASS_PROGRAM:
+ case STATE_MASS_ERASE:
+ {
+ const uint8_t fill = m_state == STATE_MASS_ERASE ? 0xff : 0;
+ verboselog( 1, "-> mass erase %02x\n", fill );
+ std::fill( std::begin( m_data ), std::end( m_data ), fill );
+ std::fill( std::begin( m_configuration_password ), std::end( m_configuration_password ), fill );
+ std::fill( std::begin( m_configuration_registers ), std::end( m_configuration_registers ), fill );
+ std::fill( std::begin( m_write_password ), std::end( m_write_password ), fill );
+ std::fill( std::begin( m_read_password ), std::end( m_read_password ), fill );
+ break;
+ }
}
m_bit = 0;