summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/zs01.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/zs01.c')
-rw-r--r--src/mame/machine/zs01.c697
1 files changed, 697 insertions, 0 deletions
diff --git a/src/mame/machine/zs01.c b/src/mame/machine/zs01.c
new file mode 100644
index 00000000000..b445c05d02c
--- /dev/null
+++ b/src/mame/machine/zs01.c
@@ -0,0 +1,697 @@
+/*
+ * zs01.c
+ *
+ * Secure SerialFlash
+ *
+ * This is a high level emulation of the PIC used in some of the System 573 security cartridges.
+ *
+ */
+
+#include "driver.h"
+#include "machine/zs01.h"
+
+#define VERBOSE_LEVEL ( 0 )
+
+INLINE void verboselog( int n_level, const char *s_fmt, ... )
+{
+ if( VERBOSE_LEVEL >= n_level )
+ {
+ va_list v;
+ char buf[ 32768 ];
+ va_start( v, s_fmt );
+ vsprintf( buf, s_fmt, v );
+ va_end( v );
+ if( cpu_getactivecpu() != -1 )
+ {
+ logerror( "%08x: %s", activecpu_get_pc(), buf );
+ }
+ else
+ {
+ logerror( "(timer) : %s", buf );
+ }
+ }
+}
+
+#define SIZE_WRITE_BUFFER ( 12 )
+#define SIZE_READ_BUFFER ( 12 )
+#define SIZE_DATA_BUFFER ( 8 )
+
+#define SIZE_RESPONSE_TO_RESET ( 4 )
+#define SIZE_KEY ( 8 )
+#define SIZE_DATA ( 4096 )
+
+struct zs01_chip
+{
+ int cs;
+ int rst;
+ int scl;
+ int sdaw;
+ int sdar;
+ int state;
+ int shift;
+ int bit;
+ int byte;
+ UINT8 write_buffer[ SIZE_WRITE_BUFFER ];
+ UINT8 read_buffer[ SIZE_READ_BUFFER ];
+ UINT8 response_key[ SIZE_KEY ];
+ UINT8 *response_to_reset;
+ UINT8 *command_key;
+ UINT8 *data_key;
+ UINT8 *data;
+ UINT8 *ds2401;
+ zs01_write_handler write;
+ zs01_read_handler read;
+};
+
+static struct zs01_chip zs01[ ZS01_MAXCHIP ];
+
+#define COMMAND_WRITE ( 0x00 )
+#define COMMAND_READ ( 0x01 )
+
+#define STATE_STOP ( 0 )
+#define STATE_RESPONSE_TO_RESET ( 1 )
+#define STATE_LOAD_COMMAND ( 2 )
+#define STATE_READ_DATA ( 3 )
+
+void zs01_init( int chip, UINT8 *data, zs01_write_handler write, zs01_read_handler read, UINT8 *ds2401 )
+{
+ int offset;
+ struct zs01_chip *c;
+
+ if( chip >= ZS01_MAXCHIP )
+ {
+ verboselog( 0, "zs01_init( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &zs01[ chip ];
+
+ if( data == NULL )
+ {
+ data = auto_malloc(
+ SIZE_RESPONSE_TO_RESET +
+ SIZE_KEY +
+ SIZE_KEY +
+ SIZE_DATA );
+ }
+
+ if( ds2401 == NULL )
+ {
+ ds2401 = auto_malloc( SIZE_DATA_BUFFER );
+ }
+
+ c->cs = 0;
+ c->rst = 0;
+ c->scl = 0;
+ c->sdaw = 0;
+ c->sdar = 0;
+ c->state = STATE_STOP;
+ c->shift = 0;
+ c->bit = 0;
+ c->byte = 0;
+ memset( c->write_buffer, 0, SIZE_WRITE_BUFFER );
+ memset( c->read_buffer, 0, SIZE_READ_BUFFER );
+ memset( c->response_key, 0, SIZE_KEY );
+
+ offset = 0;
+ c->response_to_reset = &data[ offset ]; offset += SIZE_RESPONSE_TO_RESET;
+ c->command_key = &data[ offset ]; offset += SIZE_KEY;
+ c->data_key = &data[ offset ]; offset += SIZE_KEY;
+ c->data = &data[ offset ]; offset += SIZE_DATA;
+ c->ds2401 = ds2401;
+ c->write = write;
+ c->read = read;
+
+ state_save_register_item( "zs01", chip, c->cs );
+ state_save_register_item( "zs01", chip, c->rst );
+ state_save_register_item( "zs01", chip, c->scl );
+ state_save_register_item( "zs01", chip, c->sdaw );
+ state_save_register_item( "zs01", chip, c->sdar );
+ state_save_register_item( "zs01", chip, c->state );
+ state_save_register_item( "zs01", chip, c->shift );
+ state_save_register_item( "zs01", chip, c->bit );
+ state_save_register_item( "zs01", chip, c->byte );
+ state_save_register_item_array( "zs01", chip, c->write_buffer );
+ state_save_register_item_array( "zs01", chip, c->read_buffer );
+ state_save_register_item_array( "zs01", chip, c->response_key );
+ state_save_register_item_pointer( "zs01", chip, c->response_to_reset, SIZE_RESPONSE_TO_RESET );
+ state_save_register_item_pointer( "zs01", chip, c->command_key, SIZE_KEY );
+ state_save_register_item_pointer( "zs01", chip, c->data_key, SIZE_DATA );
+}
+
+void zs01_rst_write( int chip, int rst )
+{
+ struct zs01_chip *c;
+
+ if( chip >= ZS01_MAXCHIP )
+ {
+ verboselog( 0, "zs01_rst_write( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &zs01[ chip ];
+
+ if( c->rst != rst )
+ {
+ verboselog( 2, "zs01(%d) rst=%d\n", chip, rst );
+ }
+ if( c->rst == 0 && rst != 0 && c->cs == 0 )
+ {
+ verboselog( 1, "zs01(%d) goto response to reset\n", chip );
+ c->state = STATE_RESPONSE_TO_RESET;
+ c->bit = 0;
+ c->byte = 0;
+ }
+ c->rst = rst;
+}
+
+void zs01_cs_write( int chip, int cs )
+{
+ struct zs01_chip *c;
+
+ if( chip >= ZS01_MAXCHIP )
+ {
+ verboselog( 0, "zs01_cs_write( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &zs01[ chip ];
+
+ if( c->cs != cs )
+ {
+ verboselog( 2, "zs01(%d) cs=%d\n", chip, cs );
+ }
+// if( c->cs != 0 && cs == 0 )
+// {
+// /* enable chip */
+// c->state = STATE_STOP;
+// }
+// if( c->cs == 0 && cs != 0 )
+// {
+// /* disable chip */
+// c->state = STATE_STOP;
+// /* high impendence? */
+// c->sdar = 0;
+// }
+ c->cs = cs;
+}
+
+static void zs01_decrypt( UINT8 *destination, UINT8 *source, int length, UINT8 *key, UINT8 previous_byte )
+{
+ UINT32 a0;
+ UINT32 v1;
+ UINT32 v0;
+ UINT32 a1;
+ UINT32 t1;
+ UINT32 t0;
+
+ length--;
+ if( length >= 0 )
+ {
+ do
+ {
+ t1 = source[ length ];
+ a1 = 7;
+ t0 = t1;
+
+ do
+ {
+ v1 = key[ a1 ];
+ a1--;
+ v0 = v1 & 0x1f;
+ v0 = t0 - v0;
+ v1 >>= 5;
+ v0 &= 0xff;
+ a0 = (signed)v0 >> v1;
+ v1 = 8 - v1;
+ v1 &= 7;
+ v0 = (signed)v0 << v1;
+ t0 = a0 | v0;
+ } while( a1 > 0 );
+
+ v1 = key[ 0 ];
+ a0 = previous_byte;
+ v0 = t0 & 0xff;
+ previous_byte = t1;
+ v0 = v0 - v1;
+ v0 = v0 ^ a0;
+
+ destination[ length ] = v0;
+ length--;
+ }
+ while( length >= 0 );
+ }
+}
+
+static void zs01_decrypt2( UINT8 *destination, UINT8 *source, int length, UINT8 *key, UINT8 previous_byte )
+{
+ UINT32 a0;
+ UINT32 v1;
+ UINT32 v0;
+ UINT32 a1;
+ UINT32 t2;
+ UINT32 t1;
+ UINT32 t0;
+
+ t2 = 0;
+ if( length >= 0 )
+ {
+ do
+ {
+ t1 = source[ t2 ];
+ a1 = 7;
+ t0 = t1;
+
+ do
+ {
+ v1 = key[ a1 ];
+ a1--;
+ v0 = v1 & 0x1f;
+ v0 = t0 - v0;
+ v1 >>= 5;
+ v0 &= 0xff;
+ a0 = (signed)v0 >> v1;
+ v1 = 8 - v1;
+ v1 &= 7;
+ v0 = (signed)v0 << v1;
+ t0 = a0 | v0;
+ } while( a1 > 0 );
+
+ v1 = key[ 0 ];
+ a0 = previous_byte;
+ v0 = t0 & 0xff;
+ previous_byte = t1;
+ v0 = v0 - v1;
+ v0 = v0 ^ a0;
+
+ destination[ t2 ] = v0;
+ t2++;
+
+ } while( t2 < length );
+ }
+}
+
+static void zs01_encrypt( UINT8 *destination, UINT8 *source, int length, UINT8 *key, UINT32 previous_byte )
+{
+ UINT32 t0;
+ UINT32 v0;
+ UINT32 v1;
+ UINT32 a0;
+ UINT32 a1;
+
+ length--;
+ if( length >= 0 )
+ {
+ do
+ {
+ t0 = 1;
+ v0 = source[ length ];
+ v1 = previous_byte;
+ a0 = key[ 0 ];
+ v0 ^= v1;
+ a0 += v0;
+
+ do
+ {
+ a1 = key[ t0 ];
+ t0++;
+ a0 &= 0xff;
+ v0 = a1 >> 5;
+ v1 = a0 << v0;
+ v0 = 8 - v0;
+ v0 &= 7;
+ a0 = (signed) a0 >> v0;
+ v1 |= a0;
+ v1 &= 0xff;
+ a1 &= 0x1f;
+ v1 += a1;
+ v0 = (signed) t0 < 8;
+ a0 = v1;
+
+ } while( v0 != 0 );
+
+ previous_byte = v1;
+
+ destination[ length ] = a0;
+ length--;
+
+ } while( length >= 0 );
+ }
+}
+
+static UINT16 zs01_crc( UINT8 *buffer, UINT32 length )
+{
+ UINT32 v1;
+ UINT32 a3;
+ UINT32 v0;
+ UINT32 a2;
+
+ v1 = 0xffff;
+ a3 = 0;
+
+ if( length > 0 )
+ {
+ do
+ {
+ v0 = buffer[ a3 ];
+ a2 = 7;
+ v0 = v0 << 8;
+ v1 = v1 ^ v0;
+ v0 = v1 & 0x8000;
+
+ do
+ {
+ if( v0 != 0 )
+ {
+ v0 = v1 << 1;
+ v1 = v0 ^ 0x1021;
+ }
+ else
+ {
+ v0 = v1 << 1;
+ v1 = v1 << 1;
+ }
+
+ a2--;
+ v0 = v1 & 0x8000;
+ } while( (signed) a2 >= 0 );
+
+ a3++;
+ v0 = (signed) a3 < (signed) length;
+ } while ( v0 != 0 );
+ }
+
+ v0 = ~v1 ;
+ v0 = v0 & 0xffff;
+
+ return v0;
+}
+
+static int zs01_data_offset( struct zs01_chip *c )
+{
+ int block = ( ( c->write_buffer[ 0 ] & 2 ) << 7 ) | c->write_buffer[ 1 ];
+
+ return block * SIZE_DATA_BUFFER;
+}
+
+void zs01_scl_write( int chip, int scl )
+{
+ struct zs01_chip *c;
+
+ if( chip >= ZS01_MAXCHIP )
+ {
+ verboselog( 0, "zs01_scl_write( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &zs01[ chip ];
+
+ if( c->scl != scl )
+ {
+ verboselog( 2, "zs01(%d) scl=%d\n", chip, scl );
+ }
+ if( c->cs == 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_STOP:
+ break;
+
+ case STATE_RESPONSE_TO_RESET:
+ if( c->scl != 0 && scl == 0 )
+ {
+ if( c->bit == 0 )
+ {
+ c->shift = c->response_to_reset[ c->byte ];
+ verboselog( 1, "zs01(%d) <- response_to_reset[%d]: %02x\n", chip, c->byte, c->shift );
+ }
+
+ c->sdar = ( c->shift >> 7 ) & 1;
+ c->shift <<= 1;
+ c->bit++;
+
+ if( c->bit == 8 )
+ {
+ c->bit = 0;
+ c->byte++;
+ if( c->byte == 4 )
+ {
+ c->sdar = 1;
+ verboselog( 1, "zs01(%d) goto stop\n", chip );
+ c->state = STATE_STOP;
+ }
+ }
+ }
+ break;
+
+ case STATE_LOAD_COMMAND:
+ if( c->scl == 0 && scl != 0 )
+ {
+ if( c->bit < 8 )
+ {
+ verboselog( 2, "zs01(%d) clock\n", chip );
+ c->shift <<= 1;
+ if( c->sdaw != 0 )
+ {
+ c->shift |= 1;
+ }
+ c->bit++;
+ }
+ else
+ {
+ c->sdar = 0;
+
+ switch( c->state )
+ {
+ case STATE_LOAD_COMMAND:
+ c->write_buffer[ c->byte ] = c->shift;
+ verboselog( 2, "zs01(%d) -> write_buffer[%d]: %02x\n", chip, c->byte, c->write_buffer[ c->byte ] );
+
+ c->byte++;
+ if( c->byte == SIZE_WRITE_BUFFER )
+ {
+ UINT16 crc;
+
+ zs01_decrypt( c->write_buffer, c->write_buffer, SIZE_WRITE_BUFFER, c->command_key, 0xff );
+
+ if( ( c->write_buffer[ 0 ] & 4 ) != 0 )
+ {
+ zs01_decrypt2( &c->write_buffer[ 2 ], &c->write_buffer[ 2 ], SIZE_DATA_BUFFER, c->data_key, 0x00 );
+ }
+
+ crc = zs01_crc( c->write_buffer, 10 );
+
+ if( crc == ( ( c->write_buffer[ 10 ] << 8 ) | c->write_buffer[ 11 ] ) )
+ {
+ verboselog( 1, "zs01(%d) -> command: %02x\n", chip, c->write_buffer[ 0 ] );
+ verboselog( 1, "zs01(%d) -> address: %02x\n", chip, c->write_buffer[ 1 ] );
+ verboselog( 1, "zs01(%d) -> data: %02x%02x%02x%02x%02x%02x%02x%02x\n", chip,
+ c->write_buffer[ 2 ], c->write_buffer[ 3 ], c->write_buffer[ 4 ], c->write_buffer[ 5 ],
+ c->write_buffer[ 6 ], c->write_buffer[ 7 ], c->write_buffer[ 8 ], c->write_buffer[ 9 ] );
+ verboselog( 1, "zs01(%d) -> crc: %02x%02x\n", chip, c->write_buffer[ 10 ], c->write_buffer[ 11 ] );
+
+ switch( c->write_buffer[ 0 ] & 1 )
+ {
+ case COMMAND_WRITE:
+ memcpy( &c->data[ zs01_data_offset( c ) ], &c->write_buffer[ 2 ], SIZE_DATA_BUFFER );
+
+ /* todo: find out what should be returned. */
+ memset( &c->read_buffer[ 0 ], 0, SIZE_WRITE_BUFFER );
+ break;
+
+ case COMMAND_READ:
+ /* todo: find out what should be returned. */
+ memset( &c->read_buffer[ 0 ], 0, 2 );
+
+ switch( c->write_buffer[ 1 ] )
+ {
+ case 0xfd:
+ {
+ /* TODO: use read/write to talk to the ds2401, which will require a timer. */
+ int i;
+ for( i = 0; i < SIZE_DATA_BUFFER; i++ )
+ {
+ c->read_buffer[ 2 + i ] = c->ds2401[ SIZE_DATA_BUFFER - i - 1 ];
+ }
+ }
+ break;
+ default:
+ memcpy( &c->read_buffer[ 2 ], &c->data[ zs01_data_offset( c ) ], SIZE_DATA_BUFFER );
+ break;
+ }
+
+ memcpy( c->response_key, &c->write_buffer[ 2 ], SIZE_KEY );
+ break;
+ }
+ }
+ else
+ {
+ verboselog( 0, "zs01(%d) bad crc\n", chip );
+
+ /* todo: find out what should be returned. */
+ memset( &c->read_buffer[ 0 ], 0xff, 2 );
+ }
+
+ verboselog( 1, "zs01(%d) <- status: %02x%02\n", chip,
+ c->read_buffer[ 0 ], c->read_buffer[ 1 ] );
+
+ verboselog( 1, "zs01(%d) <- data: %02x%02x%02x%02x%02x%02x%02x%02x\n", chip,
+ c->read_buffer[ 2 ], c->read_buffer[ 3 ], c->read_buffer[ 4 ], c->read_buffer[ 5 ],
+ c->read_buffer[ 6 ], c->read_buffer[ 7 ], c->read_buffer[ 8 ], c->read_buffer[ 9 ] );
+
+ crc = zs01_crc( c->read_buffer, 10 );
+ c->read_buffer[ 10 ] = crc >> 8;
+ c->read_buffer[ 11 ] = crc & 255;
+
+ zs01_encrypt( c->read_buffer, c->read_buffer, SIZE_READ_BUFFER, c->response_key, 0xff );
+
+ c->byte = 0;
+ c->state = STATE_READ_DATA;
+ }
+ break;
+ }
+
+ c->bit = 0;
+ c->shift = 0;
+ }
+ }
+ break;
+
+ case STATE_READ_DATA:
+ if( c->scl == 0 && scl != 0 )
+ {
+ if( c->bit < 8 )
+ {
+ if( c->bit == 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_READ_DATA:
+ c->shift = c->read_buffer[ c->byte ];
+ verboselog( 2, "zs01(%d) <- read_buffer[%d]: %02x\n", chip, c->byte, c->shift );
+ break;
+ }
+ }
+ c->sdar = ( c->shift >> 7 ) & 1;
+ c->shift <<= 1;
+ c->bit++;
+ }
+ else
+ {
+ c->bit = 0;
+ c->sdar = 0;
+ if( c->sdaw == 0 )
+ {
+ verboselog( 2, "zs01(%d) ack <-\n", chip );
+ c->byte++;
+ if( c->byte == SIZE_READ_BUFFER )
+ {
+ c->byte = 0;
+ c->sdar = 1;
+ c->state = STATE_LOAD_COMMAND;
+ }
+ }
+ else
+ {
+ verboselog( 2, "zs01(%d) nak <-\n", chip );
+ }
+ }
+ }
+ break;
+ }
+ }
+ c->scl = scl;
+}
+
+void zs01_sda_write( int chip, int sda )
+{
+ struct zs01_chip *c;
+
+ if( chip >= ZS01_MAXCHIP )
+ {
+ verboselog( 0, "zs01_sda_write( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &zs01[ chip ];
+
+ if( c->sdaw != sda )
+ {
+ verboselog( 2, "zs01(%d) sdaw=%d\n", chip, sda );
+ }
+ if( c->cs == 0 && c->scl != 0 )
+ {
+// if( c->sdaw == 0 && sda != 0 )
+// {
+// verboselog( 1, "zs01(%d) goto stop\n", chip );
+// c->state = STATE_STOP;
+// c->sdar = 0;
+// }
+ if( c->sdaw != 0 && sda == 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_STOP:
+ verboselog( 1, "zs01(%d) goto start\n", chip );
+ c->state = STATE_LOAD_COMMAND;
+ break;
+
+// default:
+// verboselog( 1, "zs01(%d) skipped start (default)\n", chip );
+// break;
+ }
+
+ c->bit = 0;
+ c->byte = 0;
+ c->shift = 0;
+ c->sdar = 0;
+ }
+ }
+ c->sdaw = sda;
+}
+
+int zs01_sda_read( int chip )
+{
+ struct zs01_chip *c;
+
+ if( chip >= ZS01_MAXCHIP )
+ {
+ verboselog( 0, "zs01_sda_read( %d ) chip out of range\n", chip );
+ return 1;
+ }
+
+ c = &zs01[ chip ];
+ if( c->cs != 0 )
+ {
+ verboselog( 2, "zs01(%d) not selected\n", chip );
+ return 1;
+ }
+ verboselog( 2, "zs01(%d) sdar=%d\n", chip, c->sdar );
+
+ return c->sdar;
+}
+
+static void nvram_handler_zs01( int chip, running_machine *machine, mame_file *file, int read_or_write )
+{
+ struct zs01_chip *c;
+
+ if( chip >= ZS01_MAXCHIP )
+ {
+ verboselog( 0, "nvram_handler_zs01( %d ) chip out of range\n", chip );
+ return;
+ }
+
+ c = &zs01[ chip ];
+
+ if( read_or_write )
+ {
+ mame_fwrite( file, c->data, SIZE_DATA );
+ }
+ else if( file )
+ {
+ mame_fread( file, c->data, SIZE_DATA );
+ }
+}
+
+NVRAM_HANDLER( zs01_0 ) { nvram_handler_zs01( 0, machine, file, read_or_write ); }
+NVRAM_HANDLER( zs01_1 ) { nvram_handler_zs01( 1, machine, file, read_or_write ); }