summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/machine/x76f041.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/machine/x76f041.c')
-rw-r--r--trunk/src/emu/machine/x76f041.c416
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);
+}