diff options
Diffstat (limited to 'trunk/src/emu/machine/x76f041.c')
-rw-r--r-- | trunk/src/emu/machine/x76f041.c | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/trunk/src/emu/machine/x76f041.c b/trunk/src/emu/machine/x76f041.c new file mode 100644 index 00000000000..a3ee45df84d --- /dev/null +++ b/trunk/src/emu/machine/x76f041.c @@ -0,0 +1,416 @@ +/* + * x76f041.c + * + * Secure SerialFlash + * + * The X76F041 is a Password Access Security Supervisor, containing four 128 x 8 bit SecureFlash arrays. + * Access can be controlled by three 64-bit programmable passwords, one for read operations, one for write + * operations and one for device configuration. + * + * The data sheet has an incorrect diagrams for sequential read with password, there shouldn't be an extra address after the 0xc0 command. + * + */ + +#include "emu.h" +#include "machine/x76f041.h" + +#define VERBOSE_LEVEL 0 + +inline void ATTR_PRINTF(3,4) x76f041_device::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); + logerror("x76f041 %s %s: %s", tag(), machine().describe_context(), buf); + } +} + +// device type definition +const device_type X76F041 = &device_creator<x76f041_device>; + +x76f041_device::x76f041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_secure_serial_flash(mconfig, X76F041, "X76F041", tag, owner, clock) +{ +} + +void x76f041_device::device_start() +{ + device_secure_serial_flash::device_start(); + save_item(NAME(state)); + save_item(NAME(shift)); + save_item(NAME(bit)); + save_item(NAME(byte)); + save_item(NAME(command)); + save_item(NAME(address)); + save_item(NAME(write_buffer)); + save_item(NAME(response_to_reset)); + save_item(NAME(write_password)); + save_item(NAME(read_password)); + save_item(NAME(configuration_password)); + save_item(NAME(configuration_registers)); + save_item(NAME(data)); +} + +void x76f041_device::device_reset() +{ + device_secure_serial_flash::device_reset(); + state = STATE_STOP; + shift = 0; + bit = 0; + byte = 0; + command = 0; + address = 0; + memset(write_buffer, 0, SIZE_WRITE_BUFFER); +} + +void x76f041_device::nvram_default() +{ + // region always wins + if(m_region) + { + // Ensure the size is correct though + if(m_region->bytes() != SIZE_RESPONSE_TO_RESET+SIZE_WRITE_PASSWORD+ + SIZE_READ_PASSWORD+SIZE_CONFIGURATION_PASSWORD+SIZE_CONFIGURATION_REGISTERS+SIZE_DATA) + logerror("X76F041: Wrong region length for initialization data, expected 0x%x, got 0x%x\n", + SIZE_RESPONSE_TO_RESET+SIZE_WRITE_PASSWORD+ + SIZE_READ_PASSWORD+SIZE_CONFIGURATION_PASSWORD+SIZE_CONFIGURATION_REGISTERS+SIZE_DATA, + m_region->bytes()); + else { + UINT8 *rb = m_region->base(); + int offset = 0; + memcpy(response_to_reset, rb + offset, SIZE_RESPONSE_TO_RESET); offset += SIZE_RESPONSE_TO_RESET; + memcpy(write_password, rb + offset, SIZE_WRITE_PASSWORD); offset += SIZE_WRITE_PASSWORD; + memcpy(read_password, rb + offset, SIZE_READ_PASSWORD); offset += SIZE_READ_PASSWORD; + memcpy(configuration_password, rb + offset, SIZE_CONFIGURATION_PASSWORD); offset += SIZE_CONFIGURATION_PASSWORD; + memcpy(configuration_registers, rb + offset, SIZE_CONFIGURATION_REGISTERS); offset += SIZE_CONFIGURATION_REGISTERS; + memcpy(data, rb + offset, SIZE_DATA); offset += SIZE_DATA; + return; + } + } + + // That chip isn't really usable without the passwords, so bitch + // if there's no region + logerror("X76F041: Warning, no default data provided, chip is unusable.\n"); + memset(response_to_reset, 0, SIZE_RESPONSE_TO_RESET); + memset(write_password, 0, SIZE_WRITE_PASSWORD); + memset(read_password, 0, SIZE_READ_PASSWORD); + memset(configuration_password, 0, SIZE_CONFIGURATION_PASSWORD); + memset(configuration_registers, 0, SIZE_CONFIGURATION_REGISTERS); + memset(data, 0, SIZE_DATA); +} + +void x76f041_device::cs_0() +{ + /* enable chip */ + state = STATE_STOP; +} + +void x76f041_device::cs_1() +{ + /* disable chip */ + state = STATE_STOP; + /* high impendence? */ + sdar = false; +} + +void x76f041_device::rst_0() +{ +} + +void x76f041_device::rst_1() +{ + if(!cs) { + verboselog(1, "goto response to reset\n"); + state = STATE_RESPONSE_TO_RESET; + bit = 0; + byte = 0; + } +} + +UINT8 *x76f041_device::password() +{ + switch(command & 0xe0) { + case COMMAND_WRITE: + return write_password; + case COMMAND_READ: + return read_password; + default: + return configuration_password; + } +} + +void x76f041_device::password_ok() +{ + switch(command & 0xe0) { + case COMMAND_WRITE: + state = STATE_WRITE_DATA; + break; + case COMMAND_READ: + state = STATE_READ_DATA; + break; + case COMMAND_WRITE_USE_CONFIGURATION_PASSWORD: + state = STATE_WRITE_DATA; + break; + case COMMAND_READ_USE_CONFIGURATION_PASSWORD: + state = STATE_READ_DATA; + break; + case COMMAND_CONFIGURATION: + switch( address ) { + case CONFIGURATION_PROGRAM_WRITE_PASSWORD: + break; + case CONFIGURATION_PROGRAM_READ_PASSWORD: + break; + case CONFIGURATION_PROGRAM_CONFIGURATION_PASSWORD: + break; + case CONFIGURATION_RESET_WRITE_PASSWORD: + break; + case CONFIGURATION_RESET_READ_PASSWORD: + break; + case CONFIGURATION_PROGRAM_CONFIGURATION_REGISTERS: + state = STATE_WRITE_CONFIGURATION_REGISTERS; + byte = 0; + break; + case CONFIGURATION_READ_CONFIGURATION_REGISTERS: + state = STATE_READ_CONFIGURATION_REGISTERS; + byte = 0; + break; + case CONFIGURATION_MASS_PROGRAM: + break; + case CONFIGURATION_MASS_ERASE: + break; + default: + break; + } + } +} + +void x76f041_device::load_address() +{ + /* todo: handle other bcr bits */ + int bcr; + + address = shift; + + verboselog(1, "-> address: %02x\n", address); + + if(!(command & 1 )) + bcr = configuration_registers[CONFIG_BCR1]; + else + bcr = configuration_registers[CONFIG_BCR2]; + + if(address & 0x80) + bcr >>= 4; + + if(((command & 0xe0) == COMMAND_READ && (bcr & BCR_Z) && (bcr & BCR_T)) || + ((command & 0xe0) == COMMAND_WRITE && (bcr & BCR_Z))) { + /* todo: find out when this is really checked. */ + verboselog(1, "command not allowed\n"); + state = STATE_STOP; + sdar = false; + + } else if(((command & 0xe0) == COMMAND_WRITE && !(bcr & BCR_X)) || + ((command & 0xe0) == COMMAND_READ && !(bcr & BCR_Y))) { + verboselog(1, "password not required\n"); + password_ok(); + + } else { + verboselog(1, "send password\n"); + state = STATE_LOAD_PASSWORD; + byte = 0; + } +} + +int x76f041_device::data_offset() +{ + int block_offset = ((command & 1) << 8) + address; + + // TODO: confirm block_start doesn't wrap. + + return (block_offset & 0x180) | ((block_offset + byte) & 0x7f); +} + +void x76f041_device::scl_0() +{ + if(!cs) { + switch(state) { + case STATE_RESPONSE_TO_RESET: + sdar = (response_to_reset[byte] >> bit) & 1; + verboselog(2, "in response to reset %d (%d/%d)\n", sdar, byte, bit); + bit++; + if(bit == 8) { + bit = 0; + byte++; + if( byte == 4 ) + byte = 0; + } + break; + } + } +} + +void x76f041_device::scl_1() +{ + if(!cs) { + switch(state) { + case STATE_STOP: + break; + case STATE_RESPONSE_TO_RESET: + break; + case STATE_LOAD_COMMAND: + case STATE_LOAD_ADDRESS: + case STATE_LOAD_PASSWORD: + case STATE_VERIFY_PASSWORD: + case STATE_WRITE_DATA: + case STATE_WRITE_CONFIGURATION_REGISTERS: + if(bit < 8) { + verboselog(2, "clock\n"); + shift <<= 1; + if(sdaw) + shift |= 1; + bit++; + } else { + sdar = false; + + switch(state) { + case STATE_LOAD_COMMAND: + command = shift; + verboselog(1, "-> command: %02x\n", command); + /* todo: verify command is valid? */ + state = STATE_LOAD_ADDRESS; + break; + case STATE_LOAD_ADDRESS: + load_address(); + break; + case STATE_LOAD_PASSWORD: + verboselog(1, "-> password: %02x\n", shift ); + write_buffer[byte++] = shift; + if(byte == SIZE_WRITE_BUFFER) + state = STATE_VERIFY_PASSWORD; + break; + case STATE_VERIFY_PASSWORD: + verboselog(1, "-> verify password: %02x\n", shift); + /* todo: this should probably be handled as a command */ + if(shift == 0xc0) { + /* todo: this should take 10ms before it returns ok. */ + if(!memcmp(password(), write_buffer, SIZE_WRITE_BUFFER)) + password_ok(); + else + sdar = true; + } + break; + case STATE_WRITE_DATA: + verboselog(1, "-> data: %02x\n", shift); + write_buffer[byte++] = shift; + if(byte == SIZE_WRITE_BUFFER) { + for(byte = 0; byte < SIZE_WRITE_BUFFER; byte++) + data[data_offset()] = write_buffer[byte]; + byte = 0; + verboselog(1, "data flushed\n"); + } + break; + case STATE_WRITE_CONFIGURATION_REGISTERS: + verboselog(1, "-> configuration register: %02x\n", shift); + /* todo: write after all bytes received? */ + configuration_registers[byte++] = shift; + if(byte == SIZE_CONFIGURATION_REGISTERS) + byte = 0; + break; + } + + bit = 0; + shift = 0; + } + break; + case STATE_READ_DATA: + case STATE_READ_CONFIGURATION_REGISTERS: + if(bit < 8) { + if(bit == 0) { + switch(state) { + case STATE_READ_DATA: + shift = data[data_offset()]; + verboselog(1, "<- data: %02x\n", shift); + break; + case STATE_READ_CONFIGURATION_REGISTERS: + shift = configuration_registers[byte & 7]; + verboselog(1, "<- configuration register: %02x\n", shift ); + break; + } + } + sdar = ( shift >> 7 ) & 1; + shift <<= 1; + bit++; + } else { + bit = 0; + sdar = false; + if(!sdaw) { + verboselog(2, "ack <-\n"); + byte++; + } else { + verboselog(2, "nak <-\n"); + } + } + break; + } + } +} + +void x76f041_device::sda_0() +{ + if(!cs && scl) { + switch(state) { + case STATE_STOP: + verboselog(1, "goto start (1)\n"); + state = STATE_LOAD_COMMAND; + break; + case STATE_LOAD_PASSWORD: + /* todo: this will be the 0xc0 command, but it's not handled as a command yet. */ + verboselog(1, "goto start (2)\n"); + break; + case STATE_READ_DATA: + verboselog(1, "goto load address\n"); + state = STATE_LOAD_ADDRESS; + break; + default: + verboselog(1, "skipped start (default)\n"); + break; + } + + bit = 0; + byte = 0; + shift = 0; + sdar = false; + } +} + +void x76f041_device::sda_1() +{ + if(!cs && scl) { + verboselog(1, "goto stop\n"); + state = STATE_STOP; + sdar = false; + } +} + +void x76f041_device::nvram_read(emu_file &file) +{ + file.read(response_to_reset, SIZE_RESPONSE_TO_RESET); + file.read(write_password, SIZE_WRITE_PASSWORD); + file.read(read_password, SIZE_READ_PASSWORD); + file.read(configuration_password, SIZE_CONFIGURATION_PASSWORD); + file.read(configuration_registers, SIZE_CONFIGURATION_REGISTERS); + file.read(data, SIZE_DATA); +} + +void x76f041_device::nvram_write(emu_file &file) +{ + file.write(response_to_reset, SIZE_RESPONSE_TO_RESET); + file.write(write_password, SIZE_WRITE_PASSWORD); + file.write(read_password, SIZE_READ_PASSWORD); + file.write(configuration_password, SIZE_CONFIGURATION_PASSWORD); + file.write(configuration_registers, SIZE_CONFIGURATION_REGISTERS); + file.write(data, SIZE_DATA); +} |