summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/x76f100.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/x76f100.cpp')
-rw-r--r--src/devices/machine/x76f100.cpp201
1 files changed, 159 insertions, 42 deletions
diff --git a/src/devices/machine/x76f100.cpp b/src/devices/machine/x76f100.cpp
index 4c74bb5b7ad..b64bbdf32c2 100644
--- a/src/devices/machine/x76f100.cpp
+++ b/src/devices/machine/x76f100.cpp
@@ -12,7 +12,11 @@
*/
#include "emu.h"
-#include "machine/x76f100.h"
+#include "x76f100.h"
+
+#include <cstdarg>
+#include <tuple>
+
#define VERBOSE_LEVEL ( 0 )
@@ -21,7 +25,7 @@ inline void ATTR_PRINTF( 3, 4 ) x76f100_device::verboselog( int n_level, const c
if( VERBOSE_LEVEL >= n_level )
{
va_list v;
- char buf[ 32768 ];
+ char buf[32768];
va_start( v, s_fmt );
vsprintf( buf, s_fmt, v );
va_end( v );
@@ -29,11 +33,13 @@ inline void ATTR_PRINTF( 3, 4 ) x76f100_device::verboselog( int n_level, const c
}
}
+
// device type definition
DEFINE_DEVICE_TYPE(X76F100, x76f100_device, "x76f100", "X76F100 Secure SerialFlash")
-x76f100_device::x76f100_device( const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock )
- : device_t( mconfig, X76F100, tag, owner, clock ),
+
+x76f100_device::x76f100_device( const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock ) :
+ device_t( mconfig, X76F100, tag, owner, clock ),
device_nvram_interface(mconfig, *this),
m_region(*this, DEVICE_SELF),
m_cs( 0 ),
@@ -45,13 +51,15 @@ x76f100_device::x76f100_device( const machine_config &mconfig, const char *tag,
m_shift( 0 ),
m_bit( 0 ),
m_byte( 0 ),
- m_command( 0 )
+ m_command( 0 ),
+ m_password_retry_counter( 0 ),
+ m_is_password_accepted( false )
{
}
void x76f100_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 );
save_item( NAME( m_cs ) );
save_item( NAME( m_rst ) );
@@ -63,6 +71,8 @@ void x76f100_device::device_start()
save_item( NAME( m_bit ) );
save_item( NAME( m_byte ) );
save_item( NAME( m_command ) );
+ save_item( NAME( m_password_retry_counter ) );
+ 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 ) );
@@ -70,7 +80,25 @@ void x76f100_device::device_start()
save_item( NAME( m_data ) );
}
-WRITE_LINE_MEMBER( x76f100_device::write_cs )
+void x76f100_device::device_reset()
+{
+ std::fill( std::begin( m_write_buffer ), std::end( m_write_buffer ), 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_password_retry_counter = 0;
+ m_is_password_accepted = false;
+}
+
+void x76f100_device::write_cs(int state)
{
if( m_cs != state )
{
@@ -94,7 +122,7 @@ WRITE_LINE_MEMBER( x76f100_device::write_cs )
m_cs = state;
}
-WRITE_LINE_MEMBER( x76f100_device::write_rst )
+void x76f100_device::write_rst(int state)
{
if( m_rst != state )
{
@@ -124,11 +152,13 @@ uint8_t *x76f100_device::password()
void x76f100_device::password_ok()
{
- if( ( m_command & 0xe1 ) == COMMAND_READ )
+ m_password_retry_counter = 0;
+
+ if( ( m_command & 0x81 ) == COMMAND_READ )
{
m_state = STATE_READ_DATA;
}
- else if( ( m_command & 0xe1 ) == COMMAND_WRITE )
+ else if( ( m_command & 0x81 ) == COMMAND_WRITE )
{
m_state = STATE_WRITE_DATA;
}
@@ -141,11 +171,18 @@ void x76f100_device::password_ok()
int x76f100_device::data_offset()
{
int block_offset = ( m_command >> 1 ) & 0x0f;
+ int offset = ( block_offset * sizeof( m_write_buffer ) ) + m_byte;
+
+ // Technically there are 4 bits assigned to sector values but since the data array is only 112 bytes,
+ // it will try reading out of bounds when the sector is 14 (= starts at 112) or 15 (= starts at 120).
+ // TODO: Verify what happens on real hardware when reading/writing sectors 14 and 15
+ if( offset >= sizeof ( m_data ) )
+ return -1;
- return ( block_offset * sizeof( m_write_buffer ) ) + m_byte;
+ return offset;
}
-WRITE_LINE_MEMBER( x76f100_device::write_scl )
+void x76f100_device::write_scl(int state)
{
if( m_scl != state )
{
@@ -164,7 +201,7 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
{
if( m_bit == 0 )
{
- m_shift = m_response_to_reset[ m_byte ];
+ m_shift = m_response_to_reset[m_byte];
verboselog( 1, "<- response_to_reset[%d]: %02x\n", m_byte, m_shift );
}
@@ -189,6 +226,9 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
case STATE_LOAD_PASSWORD:
case STATE_VERIFY_PASSWORD:
case STATE_WRITE_DATA:
+ // FIXME: Processing on the rising edge of the clock causes sda to change state while clock is high
+ // which is not allowed. Also need to ensure that only valid device-id's and commands
+ // are acknowledged.
if( m_scl == 0 && state != 0 )
{
if( m_bit < 8 )
@@ -212,28 +252,47 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
case STATE_LOAD_COMMAND:
m_command = m_shift;
verboselog( 1, "-> command: %02x\n", m_command );
- /* todo: verify command is valid? */
+ /* TODO: verify command is valid? */
m_state = STATE_LOAD_PASSWORD;
break;
case STATE_LOAD_PASSWORD:
verboselog( 1, "-> password: %02x\n", m_shift );
- m_write_buffer[ m_byte++ ] = m_shift;
+ m_write_buffer[m_byte++] = m_shift;
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. This becomes an issue with System 573 games that use the
+ // X76F100 as an install cartridge. The boot process first tries to use the
+ // game cartridge password and if not accepted will try the install cartridge
+ // password and then enter installation mode if accepted.
+ m_is_password_accepted = memcmp( password(), m_write_buffer, sizeof( m_write_buffer ) ) == 0;
+ if( !m_is_password_accepted )
+ {
+ m_password_retry_counter++;
+ if( m_password_retry_counter >= 8 )
+ {
+ std::fill( std::begin( m_read_password ), std::end( m_read_password ), 0 );
+ std::fill( std::begin( m_write_password ), std::end( m_write_password ), 0 );
+ std::fill( std::begin( m_data ), std::end( m_data ), 0 );
+ m_password_retry_counter = 0;
+ }
+ }
}
break;
case STATE_VERIFY_PASSWORD:
verboselog( 1, "-> verify password: %02x\n", m_shift );
- /* todo: this should probably be handled as a command */
+ /* TODO: this should probably be handled as a command */
if( m_shift == COMMAND_ACK_PASSWORD )
{
- /* todo: this should take 10ms before it returns ok. */
- if( memcmp( password(), m_write_buffer, sizeof( m_write_buffer ) ) == 0 )
+ /* TODO: this should take 10ms before it returns ok. */
+ if( m_is_password_accepted )
{
password_ok();
}
@@ -246,15 +305,35 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
case STATE_WRITE_DATA:
verboselog( 2, "-> data: %02x\n", m_shift );
- m_write_buffer[ m_byte++ ] = m_shift;
+ m_write_buffer[m_byte++] = m_shift;
if( m_byte == sizeof( m_write_buffer ) )
{
- for( m_byte = 0; m_byte < sizeof( m_write_buffer ); m_byte++ )
+ if( m_command == COMMAND_CHANGE_WRITE_PASSWORD )
{
- int offset = data_offset();
- verboselog( 1, "-> data[ %03x ]: %02x\n", offset, m_write_buffer[ m_byte ] );
- m_data[ offset ] = m_write_buffer[ m_byte ];
+ std::copy( std::begin( m_write_buffer ), std::end( m_write_buffer ), std::begin( m_write_password ) );
+ }
+ else if( m_command == COMMAND_CHANGE_READ_PASSWORD )
+ {
+ std::copy( std::begin( m_write_buffer ), std::end( m_write_buffer ), std::begin( m_read_password ) );
+ }
+ else
+ {
+ for( m_byte = 0; m_byte < sizeof( m_write_buffer ); m_byte++ )
+ {
+ int offset = data_offset();
+
+ if( offset != -1 )
+ {
+ verboselog( 1, "-> data[%03x]: %02x\n", offset, m_write_buffer[m_byte] );
+ m_data[offset] = m_write_buffer[m_byte];
+ }
+ else
+ {
+ verboselog( 1, "-> attempted to write %02x out of bounds\n", m_write_buffer[m_byte] );
+ break;
+ }
+ }
}
m_byte = 0;
@@ -271,6 +350,8 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
break;
case STATE_READ_DATA:
+ // FIXME: Processing on the rising edge of the clock causes sda to change state while clock is high
+ // which is not allowed.
if( m_scl == 0 && state != 0 )
{
if( m_bit < 8 )
@@ -283,8 +364,18 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
{
case STATE_READ_DATA:
offset = data_offset();
- m_shift = m_data[ offset ];
- verboselog( 1, "<- data[ %02x ]: %02x\n", offset, m_shift );
+
+ if( offset != -1 )
+ {
+ m_shift = m_data[offset];
+ verboselog( 1, "<- data[%02x]: %02x\n", offset, m_shift );
+ }
+ else
+ {
+ m_shift = 0;
+ verboselog( 1, "<- attempted to read out of bounds\n" );
+ }
+
break;
}
}
@@ -316,7 +407,7 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
m_scl = state;
}
-WRITE_LINE_MEMBER( x76f100_device::write_sda )
+void x76f100_device::write_sda(int state)
{
if( m_sdaw != state )
{
@@ -342,7 +433,7 @@ WRITE_LINE_MEMBER( x76f100_device::write_sda )
break;
case STATE_LOAD_PASSWORD:
- /* todo: this will be the 0xc0 command, but it's not handled as a command yet. */
+ /* TODO: this will be the 0xc0 command, but it's not handled as a command yet. */
verboselog( 1, "goto start\n" );
break;
@@ -367,7 +458,7 @@ WRITE_LINE_MEMBER( x76f100_device::write_sda )
m_sdaw = state;
}
-READ_LINE_MEMBER( x76f100_device::read_sda )
+int x76f100_device::read_sda()
{
if( m_cs != 0 )
{
@@ -381,10 +472,10 @@ READ_LINE_MEMBER( x76f100_device::read_sda )
void x76f100_device::nvram_default()
{
- m_response_to_reset[ 0 ] = 0x19;
- m_response_to_reset[ 1 ] = 0x00;
- m_response_to_reset[ 2 ] = 0xaa;
- m_response_to_reset[ 3 ] = 0x55,
+ m_response_to_reset[0] = 0x19;
+ m_response_to_reset[1] = 0x00;
+ m_response_to_reset[2] = 0xaa;
+ m_response_to_reset[3] = 0x55,
memset( m_write_password, 0, sizeof( m_write_password ) );
memset( m_read_password, 0, sizeof( m_read_password ) );
@@ -411,18 +502,44 @@ void x76f100_device::nvram_default()
}
}
-void x76f100_device::nvram_read( emu_file &file )
+bool x76f100_device::nvram_read( util::read_stream &file )
{
- file.read( m_response_to_reset, sizeof( m_response_to_reset ) );
- file.read( m_write_password, sizeof( m_write_password ) );
- file.read( m_read_password, sizeof( m_read_password ) );
- file.read( m_data, sizeof( m_data ) );
+ std::error_condition err;
+ size_t actual;
+
+ std::tie( err, actual ) = read( file, m_response_to_reset, sizeof( m_response_to_reset ) );
+ if( err || ( sizeof( m_response_to_reset ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_write_password, sizeof( m_write_password ) );
+ if( err || ( sizeof( m_write_password ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_read_password, sizeof( m_read_password ) );
+ if( err || ( sizeof( m_read_password ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_data, sizeof( m_data ) );
+ if( err || ( sizeof( m_data ) != actual ) )
+ return false;
+
+ return true;
}
-void x76f100_device::nvram_write( emu_file &file )
+bool x76f100_device::nvram_write( util::write_stream &file )
{
- file.write( m_response_to_reset, sizeof( m_response_to_reset ) );
- file.write( m_write_password, sizeof( m_write_password ) );
- file.write( m_read_password, sizeof( m_read_password ) );
- file.write( m_data, sizeof( m_data ) );
+ std::error_condition err;
+ size_t actual;
+
+ std::tie( err, actual ) = write( file, m_response_to_reset, sizeof( m_response_to_reset ) );
+ if ( err )
+ return false;
+ std::tie( err, actual ) = write( file, m_write_password, sizeof( m_write_password ) );
+ if ( err )
+ return false;
+ std::tie( err, actual ) = write( file, m_read_password, sizeof( m_read_password ) );
+ if ( err )
+ return false;
+ std::tie( err, actual ) = write( file, m_data, sizeof( m_data ) );
+ if ( err )
+ return false;
+
+ return true;
}