diff options
Diffstat (limited to 'src/emu/machine/intelfsh.c')
-rw-r--r-- | src/emu/machine/intelfsh.c | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/src/emu/machine/intelfsh.c b/src/emu/machine/intelfsh.c new file mode 100644 index 00000000000..54b894cb5d7 --- /dev/null +++ b/src/emu/machine/intelfsh.c @@ -0,0 +1,493 @@ +/* + Flash ROM emulation + + Explicitly supports: + Intel 28F016S5 (byte-wide) + AMD/Fujitsu 29F016 (byte-wide) + Sharp LH28F400 (word-wide) + + Flash ROMs use a standardized command set accross manufacturers, + so this emulation should work even for non-Intel and non-Sharp chips + as long as the game doesn't query the maker ID. +*/ + +#include "driver.h" +#include "intelfsh.h" + +enum +{ + FM_NORMAL, // normal read/write + FM_READID, // read ID + FM_READSTATUS, // read status + FM_WRITEPART1, // first half of programming, awaiting second + FM_CLEARPART1, // first half of clear, awaiting second + FM_SETMASTER, // first half of set master lock, awaiting on/off + FM_READAMDID1, // part 1 of alt ID sequence + FM_READAMDID2, // part 2 of alt ID sequence + FM_READAMDID3, // part 3 of alt ID sequence + FM_ERASEAMD1, // part 1 of AMD erase sequence + FM_ERASEAMD2, // part 2 of AMD erase sequence + FM_ERASEAMD3, // part 3 of AMD erase sequence + FM_ERASEAMD4, // part 4 of AMD erase sequence + FM_BYTEPROGRAM, +}; + +struct flash_chip +{ + int type; + int size; + int bits; + int status; + INT32 flash_mode; + INT32 flash_master_lock; + int device_id; + int maker_id; + emu_timer *timer; + void *flash_memory; +}; + +static struct flash_chip chips[FLASH_CHIPS_MAX]; + +static TIMER_CALLBACK_PTR( erase_finished ) +{ + struct flash_chip *c = param; + + switch( c->flash_mode ) + { + case FM_READSTATUS: + c->status = 0x80; + break; + + case FM_ERASEAMD4: + c->flash_mode = FM_NORMAL; + break; + } +} + +void* intelflash_getmemptr(int chip) +{ + struct flash_chip *c; + if( chip >= FLASH_CHIPS_MAX ) + { + logerror( "intelflash_init: invalid chip %d\n", chip ); + return 0; + } + c = &chips[ chip ]; + + return c->flash_memory; +} + +void intelflash_init(int chip, int type, void *data) +{ + struct flash_chip *c; + if( chip >= FLASH_CHIPS_MAX ) + { + logerror( "intelflash_init: invalid chip %d\n", chip ); + return; + } + c = &chips[ chip ]; + + c->type = type; + switch( c->type ) + { + case FLASH_INTEL_28F016S5: + case FLASH_SHARP_LH28F016S: + c->bits = 8; + c->size = 0x200000; + c->maker_id = 0x89; + c->device_id = 0xaa; + break; + case FLASH_SHARP_LH28F400: + c->bits = 16; + c->size = 0x80000; + c->maker_id = 0xb0; + c->device_id = 0xed; + break; + case FLASH_FUJITSU_29F016A: + c->bits = 8; + c->size = 0x200000; + c->maker_id = 0x04; + c->device_id = 0xad; + break; + case FLASH_INTEL_E28F008SA: + c->bits = 8; + c->size = 0x100000; + c->maker_id = 0x89; + c->device_id = 0xa2; + break; + case FLASH_INTEL_TE28F160: + c->bits = 16; + c->size = 0x200000; + c->maker_id = 0xb0; + c->device_id = 0xd0; + break; + } + if( data == NULL ) + { + data = auto_malloc( c->size ); + memset( data, 0xff, c->size ); + } + + c->status = 0x80; + c->flash_mode = FM_NORMAL; + c->flash_master_lock = 0; + c->timer = timer_alloc_ptr(erase_finished, c); + c->flash_memory = data; + + state_save_register_item( "intelfsh", chip, c->status ); + state_save_register_item( "intelfsh", chip, c->flash_mode ); + state_save_register_item( "intelfsh", chip, c->flash_master_lock ); + state_save_register_memory( "intelfsh", chip, "flash_memory", c->flash_memory, c->bits/8, c->size / (c->bits/8) ); +} + +UINT32 intelflash_read(int chip, UINT32 address) +{ + UINT32 data = 0; + struct flash_chip *c; + if( chip >= FLASH_CHIPS_MAX ) + { + logerror( "intelflash_read: invalid chip %d\n", chip ); + return 0; + } + c = &chips[ chip ]; + + switch( c->flash_mode ) + { + default: + case FM_NORMAL: + switch( c->bits ) + { + case 8: + { + UINT8 *flash_memory = c->flash_memory; + data = flash_memory[ address ]; + } + break; + case 16: + { + UINT16 *flash_memory = c->flash_memory; + data = flash_memory[ address ]; + } + break; + } + break; + case FM_READSTATUS: + data = c->status; + break; + case FM_READAMDID3: + switch (address) + { + case 0: data = c->maker_id; break; + case 1: data = c->device_id; break; + case 2: data = 0; break; + } + break; + case FM_READID: + switch (address) + { + case 0: // maker ID + data = c->maker_id; + break; + case 1: // chip ID + data = c->device_id; + break; + case 2: // block lock config + data = 0; // we don't support this yet + break; + case 3: // master lock config + if (c->flash_master_lock) + { + data = 1; + } + else + { + data = 0; + } + break; + } + break; + case FM_ERASEAMD4: + c->status ^= ( 1 << 6 ) | ( 1 << 2 ); + data = c->status; + break; + } + +// logerror( "%08x: intelflash_read( %d, %08x ) %08x\n", activecpu_get_pc(), chip, address, data ); + + return data; +} + +void intelflash_write(int chip, UINT32 address, UINT32 data) +{ + struct flash_chip *c; + if( chip >= FLASH_CHIPS_MAX ) + { + logerror( "intelflash_write: invalid chip %d\n", chip ); + return; + } + c = &chips[ chip ]; + +// logerror( "%08x: intelflash_write( %d, %08x, %08x )\n", activecpu_get_pc(), chip, address, data ); + + switch( c->flash_mode ) + { + case FM_NORMAL: + case FM_READSTATUS: + case FM_READID: + case FM_READAMDID3: + switch( data & 0xff ) + { + case 0xf0: + case 0xff: // reset chip mode + c->flash_mode = FM_NORMAL; + break; + case 0x90: // read ID + c->flash_mode = FM_READID; + break; + case 0x40: + case 0x10: // program + c->flash_mode = FM_WRITEPART1; + break; + case 0x50: // clear status reg + c->status = 0x80; + c->flash_mode = FM_READSTATUS; + break; + case 0x20: // block erase + c->flash_mode = FM_CLEARPART1; + break; + case 0x60: // set master lock + c->flash_mode = FM_SETMASTER; + break; + case 0x70: // read status + c->flash_mode = FM_READSTATUS; + break; + case 0xaa: // AMD ID select part 1 + if( ( address & 0xffff ) == 0x555 ) + { + c->flash_mode = FM_READAMDID1; + } + break; + default: + logerror( "Unknown flash mode byte %x\n", data & 0xff ); + break; + } + break; + case FM_READAMDID1: + if( ( address & 0xffff ) == 0x2aa && ( data & 0xff ) == 0x55 ) + { + c->flash_mode = FM_READAMDID2; + } + else + { + logerror( "unexpected %08x=%02x in FM_READAMDID1\n", address, data & 0xff ); + c->flash_mode = FM_NORMAL; + } + break; + case FM_READAMDID2: + if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0x90 ) + { + c->flash_mode = FM_READAMDID3; + } + else if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0x80 ) + { + c->flash_mode = FM_ERASEAMD1; + } + else if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0xa0 ) + { + c->flash_mode = FM_BYTEPROGRAM; + } + else if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0xf0 ) + { + c->flash_mode = FM_NORMAL; + } + else + { + logerror( "unexpected %08x=%02x in FM_READAMDID2\n", address, data & 0xff ); + c->flash_mode = FM_NORMAL; + } + break; + case FM_ERASEAMD1: + if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0xaa ) + { + c->flash_mode = FM_ERASEAMD2; + } + else + { + logerror( "unexpected %08x=%02x in FM_ERASEAMD1\n", address, data & 0xff ); + } + break; + case FM_ERASEAMD2: + if( ( address & 0xffff ) == 0x2aa && ( data & 0xff ) == 0x55 ) + { + c->flash_mode = FM_ERASEAMD3; + } + else + { + logerror( "unexpected %08x=%02x in FM_ERASEAMD2\n", address, data & 0xff ); + } + break; + case FM_ERASEAMD3: + if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0x10 ) + { + // chip erase + memset( c->flash_memory, 0xff, c->size); + + c->status = 1 << 3; + c->flash_mode = FM_ERASEAMD4; + + timer_adjust_ptr( c->timer, ATTOTIME_IN_SEC( 17 ), attotime_zero ); + } + else if( ( data & 0xff ) == 0x30 ) + { + // sector erase + // clear the 64k block containing the current address to all 0xffs + switch( c->bits ) + { + case 8: + { + UINT8 *flash_memory = c->flash_memory; + memset( &flash_memory[ address & ~0xffff ], 0xff, 64 * 1024 ); + } + break; + case 16: + { + UINT16 *flash_memory = c->flash_memory; + memset( &flash_memory[ address & ~0x7fff ], 0xff, 64 * 1024 ); + } + break; + } + + c->status = 1 << 3; + c->flash_mode = FM_ERASEAMD4; + + timer_adjust_ptr( c->timer, ATTOTIME_IN_SEC( 1 ), attotime_zero ); + } + else + { + logerror( "unexpected %08x=%02x in FM_ERASEAMD3\n", address, data & 0xff ); + } + break; + case FM_BYTEPROGRAM: + switch( c->bits ) + { + case 8: + { + UINT8 *flash_memory = c->flash_memory; + flash_memory[ address ] = data; + } + break; + default: + logerror( "FM_BYTEPROGRAM not supported when c->bits == %d\n", c->bits ); + break; + } + c->flash_mode = FM_NORMAL; + break; + case FM_WRITEPART1: + switch( c->bits ) + { + case 8: + { + UINT8 *flash_memory = c->flash_memory; + flash_memory[ address ] = data; + } + break; + case 16: + { + UINT16 *flash_memory = c->flash_memory; + flash_memory[ address ] = data; + } + break; + default: + logerror( "FM_WRITEPART1 not supported when c->bits == %d\n", c->bits ); + break; + } + c->status = 0x80; + c->flash_mode = FM_READSTATUS; + break; + case FM_CLEARPART1: + if( ( data & 0xff ) == 0xd0 ) + { + // clear the 64k block containing the current address to all 0xffs + switch( c->bits ) + { + case 8: + { + UINT8 *flash_memory = c->flash_memory; + memset( &flash_memory[ address & ~0xffff ], 0xff, 64 * 1024 ); + } + break; + case 16: + { + UINT16 *flash_memory = c->flash_memory; + memset( &flash_memory[ address & ~0x7fff ], 0xff, 64 * 1024 ); + } + break; + default: + logerror( "FM_CLEARPART1 not supported when c->bits == %d\n", c->bits ); + break; + } + c->status = 0x00; + c->flash_mode = FM_READSTATUS; + + timer_adjust_ptr( c->timer, ATTOTIME_IN_SEC( 1 ), attotime_zero ); + break; + } + else + { + logerror( "unexpected %02x in FM_CLEARPART1\n", data & 0xff ); + } + break; + case FM_SETMASTER: + switch( data & 0xff ) + { + case 0xf1: + c->flash_master_lock = 1; + break; + case 0xd0: + c->flash_master_lock = 0; + break; + default: + logerror( "unexpected %08x=%02x in FM_SETMASTER:\n", address, data & 0xff ); + break; + } + c->flash_mode = FM_NORMAL; + break; + } +} + +void nvram_handler_intelflash(running_machine *machine, int chip,mame_file *file,int read_or_write) +{ + struct flash_chip *c; + if( chip >= FLASH_CHIPS_MAX ) + { + logerror( "intelflash_nvram: invalid chip %d\n", chip ); + return; + } + c = &chips[ chip ]; + + switch( c->bits ) + { + case 8: + if (read_or_write) + { + mame_fwrite( file, c->flash_memory, c->size ); + } + else if (file) + { + mame_fread( file, c->flash_memory, c->size ); + } + break; + case 16: + if (read_or_write) + { + /// TODO: endian conversion + mame_fwrite( file, c->flash_memory, c->size ); + } + else if (file) + { + mame_fread( file, c->flash_memory, c->size ); + /// TODO: endian conversion + } + break; + } +} |