diff options
author | 2016-05-01 12:55:22 +0200 | |
---|---|---|
committer | 2016-05-01 12:55:22 +0200 | |
commit | 13855d24046810569161bb02ced7fd2de88d7476 (patch) | |
tree | f407a87ca7daff7b256fd89541bdf67fc46e0c86 /src/devices | |
parent | 11ceaee97fccc15ebf033f8b54127e015ed02b1c (diff) |
Fixed ti drivers (nw)
Diffstat (limited to 'src/devices')
-rw-r--r-- | src/devices/machine/smartmed.cpp | 791 | ||||
-rw-r--r-- | src/devices/machine/smartmed.h | 237 |
2 files changed, 1028 insertions, 0 deletions
diff --git a/src/devices/machine/smartmed.cpp b/src/devices/machine/smartmed.cpp new file mode 100644 index 00000000000..9ba88c447fe --- /dev/null +++ b/src/devices/machine/smartmed.cpp @@ -0,0 +1,791 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +/* + smartmed.c: SmartMedia Flash ROM emulation + + The SmartMedia is a Flash ROM in a fancy card. It is used in a variety of + digital devices (still cameras...) and can be interfaced with a computer. + + References: + Datasheets for various SmartMedia chips were found on Samsung and Toshiba's + sites (http://www.toshiba.com/taec and + http://www.samsung.com/Products/Semiconductor/Flash/FlashCard/SmartMedia) + + TODO: + * support multi-plane mode? + * use HD-format images instead of our experimental custom format? + + Raphael Nabet 2004 +*/ + +#include "emu.h" +#include "smartmed.h" + + +#define MAX_SMARTMEDIA 1 + +/* machine-independent big-endian 32-bit integer */ +struct UINT32BE +{ + UINT8 bytes[4]; +}; + +static inline UINT32 get_UINT32BE(UINT32BE word) +{ + return (word.bytes[0] << 24) | (word.bytes[1] << 16) | (word.bytes[2] << 8) | word.bytes[3]; +} + +#ifdef UNUSED_FUNCTION +static inline void set_UINT32BE(UINT32BE *word, UINT32 data) +{ + word->bytes[0] = (data >> 24) & 0xff; + word->bytes[1] = (data >> 16) & 0xff; + word->bytes[2] = (data >> 8) & 0xff; + word->bytes[3] = data & 0xff; +} +#endif + +/* SmartMedia image header */ +struct SM_disk_image_header +{ + UINT8 version; + UINT32BE page_data_size; + UINT32BE page_total_size; + UINT32BE num_pages; + UINT32BE log2_pages_per_block; +}; + +struct disk_image_format_2_header +{ + UINT8 data1[3]; + UINT8 padding1[256-3]; + UINT8 data2[16]; + UINT8 data3[16]; + UINT8 padding2[768-32]; +}; + +enum +{ + header_len = sizeof(SM_disk_image_header) +}; + + +const device_type NAND = &device_creator<nand_device>; + +nand_device::nand_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NAND, "NAND Flash Memory", tag, owner, clock, "nand", __FILE__), + m_page_data_size(0), + m_page_total_size(0), + m_num_pages(0), + m_log2_pages_per_block(0), + m_pagereg(nullptr), + m_id_len(0), + m_col_address_cycles(0), + m_row_address_cycles(0), + m_sequential_row_read(0), + m_write_rnb(*this) +{ + memset(m_id, 0, sizeof(m_id)); +} + +nand_device::nand_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_page_data_size(0), + m_page_total_size(0), + m_num_pages(0), + m_log2_pages_per_block(0), + m_pagereg(nullptr), + m_id_len(0), + m_col_address_cycles(0), + m_row_address_cycles(0), + m_sequential_row_read(0), + m_write_rnb(*this) +{ + memset(m_id, 0, sizeof(m_id)); +} + +/* + Init a SmartMedia image +*/ +void nand_device::device_start() +{ + m_data_ptr = nullptr; + m_data_uid_ptr = nullptr; + m_mode = SM_M_INIT; + m_pointer_mode = SM_PM_A; + m_page_addr = 0; + m_byte_addr = 0; + m_status = 0xC0; + m_accumulated_status = 0; + m_mp_opcode = 0; + m_mode_3065 = 0; + m_pagereg = std::make_unique<UINT8[]>(m_page_total_size); + + #ifdef SMARTMEDIA_IMAGE_SAVE + m_image_format = 0; + #endif + m_write_rnb.resolve_safe(); +} + +/* + Load a SmartMedia image +*/ +bool smartmedia_image_device::smartmedia_format_1() +{ + SM_disk_image_header custom_header; + int bytes_read; + + bytes_read = fread(&custom_header, sizeof(custom_header)); + if (bytes_read != sizeof(custom_header)) + { + return IMAGE_INIT_FAIL; + } + + if (custom_header.version > 1) + { + return IMAGE_INIT_FAIL; + } + + m_page_data_size = get_UINT32BE(custom_header.page_data_size); + m_page_total_size = get_UINT32BE(custom_header.page_total_size); + m_num_pages = get_UINT32BE(custom_header.num_pages); + m_log2_pages_per_block = get_UINT32BE(custom_header.log2_pages_per_block); + m_data_ptr = auto_alloc_array(machine(), UINT8, m_page_total_size*m_num_pages); + m_data_uid_ptr = std::make_unique<UINT8[]>(256 + 16); + m_mode = SM_M_INIT; + m_pointer_mode = SM_PM_A; + m_page_addr = 0; + m_byte_addr = 0; + m_status = 0x40; + if (!is_readonly()) + m_status |= 0x80; + m_accumulated_status = 0; + m_pagereg = std::make_unique<UINT8[]>(m_page_total_size); + memset( m_id, 0, sizeof( m_id)); + m_id_len = 0; + m_col_address_cycles = 1; + m_row_address_cycles = (m_num_pages > 0x10000) ? 3 : 2; + m_sequential_row_read = 1; + + if (custom_header.version == 0) + { + m_id_len = 2; + fread(m_id, m_id_len); + fread(&m_mp_opcode, 1); + } + else if (custom_header.version == 1) + { + m_id_len = 3; + fread(m_id, m_id_len); + fread(&m_mp_opcode, 1); + fread(m_data_uid_ptr.get(), 256 + 16); + } + fread(m_data_ptr, m_page_total_size*m_num_pages); + + #ifdef SMARTMEDIA_IMAGE_SAVE + m_image_format = 1; + #endif + + return IMAGE_INIT_PASS; +} + +int smartmedia_image_device::detect_geometry( UINT8 id1, UINT8 id2) +{ + int result = FALSE; + + switch (id1) + { + case 0xEC : + { + switch (id2) + { + case 0xA4 : m_page_data_size = 0x0100; m_num_pages = 0x00800; m_page_total_size = 0x0108; m_log2_pages_per_block = 0; result = TRUE; break; + case 0x6E : m_page_data_size = 0x0100; m_num_pages = 0x01000; m_page_total_size = 0x0108; m_log2_pages_per_block = 0; result = TRUE; break; + case 0xEA : m_page_data_size = 0x0100; m_num_pages = 0x02000; m_page_total_size = 0x0108; m_log2_pages_per_block = 4; result = TRUE; break; + case 0xE3 : m_page_data_size = 0x0200; m_num_pages = 0x02000; m_page_total_size = 0x0210; m_log2_pages_per_block = 4; result = TRUE; break; + case 0xE6 : m_page_data_size = 0x0200; m_num_pages = 0x04000; m_page_total_size = 0x0210; m_log2_pages_per_block = 4; result = TRUE; break; + case 0x73 : m_page_data_size = 0x0200; m_num_pages = 0x08000; m_page_total_size = 0x0210; m_log2_pages_per_block = 5; result = TRUE; break; + case 0x75 : m_page_data_size = 0x0200; m_num_pages = 0x10000; m_page_total_size = 0x0210; m_log2_pages_per_block = 5; result = TRUE; break; + case 0x76 : m_page_data_size = 0x0200; m_num_pages = 0x20000; m_page_total_size = 0x0210; m_log2_pages_per_block = 5; result = TRUE; break; + case 0x79 : m_page_data_size = 0x0200; m_num_pages = 0x40000; m_page_total_size = 0x0210; m_log2_pages_per_block = 5; result = TRUE; break; + } + } + break; + case 0x98 : + { + switch (id2) + { + case 0x75 : m_page_data_size = 0x0200; m_num_pages = 0x10000; m_page_total_size = 0x0210; m_log2_pages_per_block = 5; result = TRUE; break; + } + } + break; + } + + return result; +} + +bool smartmedia_image_device::smartmedia_format_2() +{ + disk_image_format_2_header custom_header; + int bytes_read, i, j; + + bytes_read = fread(&custom_header, sizeof(custom_header)); + if (bytes_read != sizeof(custom_header)) + { + return IMAGE_INIT_FAIL; + } + + if ((custom_header.data1[0] != 0xEC) && (custom_header.data1[0] != 0x98)) + { + return IMAGE_INIT_FAIL; + } + + if (!detect_geometry(custom_header.data1[0], custom_header.data1[1])) + { + return IMAGE_INIT_FAIL; + } + + m_data_ptr = auto_alloc_array(machine(), UINT8, m_page_total_size*m_num_pages); + m_data_uid_ptr = std::make_unique<UINT8[]>(256 + 16); + m_mode = SM_M_INIT; + m_pointer_mode = SM_PM_A; + m_page_addr = 0; + m_byte_addr = 0; + m_status = 0x40; + if (!is_readonly()) + m_status |= 0x80; + m_accumulated_status = 0; + m_pagereg = std::make_unique<UINT8[]>(m_page_total_size); + m_id_len = 3; + memcpy( m_id, custom_header.data1, m_id_len); + m_mp_opcode = 0; + m_col_address_cycles = 1; + m_row_address_cycles = (m_num_pages > 0x10000) ? 3 : 2; + m_sequential_row_read = 1; + + for (i=0;i<8;i++) + { + memcpy( m_data_uid_ptr.get() + i * 32, custom_header.data2, 16); + for (j=0;j<16;j++) m_data_uid_ptr[i*32+16+j] = custom_header.data2[j] ^ 0xFF; + } + memcpy( m_data_uid_ptr.get() + 256, custom_header.data3, 16); + + fread(m_data_ptr, m_page_total_size*m_num_pages); + + #ifdef SMARTMEDIA_IMAGE_SAVE + m_image_format = 2; + #endif + + return IMAGE_INIT_PASS; +} + +bool smartmedia_image_device::call_load() +{ + int result; + UINT64 position; + // try format 1 + position = ftell(); + result = smartmedia_format_1(); + if (result != IMAGE_INIT_PASS) + { + // try format 2 + fseek( position, SEEK_SET); + result = smartmedia_format_2(); + } + return result; +} + +/* + Unload a SmartMedia image +*/ +void smartmedia_image_device::call_unload() +{ + #ifdef SMARTMEDIA_IMAGE_SAVE + if (!is_readonly()) + { + if (m_image_format == 1) + { + SM_disk_image_header custom_header; + int bytes_read; + fseek( 0, SEEK_SET); + bytes_read = fread( &custom_header, sizeof( custom_header)); + if (bytes_read == sizeof( custom_header)) + { + if (custom_header.version == 0) + { + fseek( 2 + 1, SEEK_CUR); + fwrite( m_data_ptr, m_page_total_size * m_num_pages); + } + else if (custom_header.version == 1) + { + fseek( 3 + 1 + 256 + 16, SEEK_CUR); + fwrite( m_data_ptr, m_page_total_size * m_num_pages); + } + } + } + else if (m_image_format == 2) + { + fseek( sizeof( disk_image_format_2_header), SEEK_SET); + fwrite( m_data_ptr, m_page_total_size * m_num_pages); + } + } + #endif + + m_page_data_size = 0; + m_page_total_size = 0; + m_num_pages = 0; + m_log2_pages_per_block = 0; + m_data_ptr = nullptr; + m_data_uid_ptr = nullptr; + m_mode = SM_M_INIT; + m_pointer_mode = SM_PM_A; + m_page_addr = 0; + m_byte_addr = 0; + m_status = 0xC0; + m_accumulated_status = 0; + m_pagereg = std::make_unique<UINT8[]>(m_page_total_size); + memset( m_id, 0, sizeof( m_id)); + m_id_len = 0; + m_mp_opcode = 0; + m_mode_3065 = 0; + m_col_address_cycles = 0; + m_row_address_cycles = 0; + m_sequential_row_read = 0; + + #ifdef SMARTMEDIA_IMAGE_SAVE + m_image_format = 0; + #endif + + return; +} + +int nand_device::is_present() +{ + return m_num_pages != 0; +} + +int nand_device::is_protected() +{ + return (m_status & 0x80) == 0; +} + +int nand_device::is_busy() +{ + return (m_status & 0x40) == 0; +} + +void nand_device::set_data_ptr(void *ptr) +{ + m_data_ptr = (UINT8 *)ptr; +} + +/* + write a byte to SmartMedia command port +*/ +void nand_device::command_w(UINT8 data) +{ + if (!is_present()) + return; + + switch (data) + { + case 0xff: // Reset + m_mode = SM_M_INIT; + m_pointer_mode = SM_PM_A; + m_status = (m_status & 0x80) | 0x40; + m_accumulated_status = 0; + m_mode_3065 = 0; + if (!m_write_rnb.isnull()) + { + m_write_rnb( 0); + m_write_rnb( 1); + } + break; + case 0x00: // Read (1st cycle) + m_mode = SM_M_READ; + m_pointer_mode = SM_PM_A; + m_page_addr = 0; + m_addr_load_ptr = 0; + break; + case 0x01: + if (m_page_data_size != 512) + { + logerror("smartmedia: unsupported upper data field select (256-byte pages)\n"); + m_mode = SM_M_INIT; + } + else + { + m_mode = SM_M_READ; + m_pointer_mode = SM_PM_B; + m_page_addr = 0; + m_addr_load_ptr = 0; + } + break; + case 0x50: + if (m_page_data_size > 512) + { + logerror("smartmedia: unsupported spare area select\n"); + m_mode = SM_M_INIT; + } + else + { + m_mode = SM_M_READ; + m_pointer_mode = SM_PM_C; + m_page_addr = 0; + m_addr_load_ptr = 0; + } + break; + case 0x80: // Page Program (1st cycle) + m_mode = SM_M_PROGRAM; + m_page_addr = 0; + m_addr_load_ptr = 0; + m_program_byte_count = 0; + memset(m_pagereg.get(), 0xff, m_page_total_size); + break; + case 0x10: // Page Program (2nd cycle) + case 0x15: + if ((m_mode != SM_M_PROGRAM) && (m_mode != SM_M_RANDOM_DATA_INPUT)) + { + logerror("smartmedia: illegal page program confirm command\n"); + m_mode = SM_M_INIT; + } + else + { + int i; + m_status = (m_status & 0x80) | m_accumulated_status; + //logerror( "smartmedia: program, page_addr %08X\n", m_page_addr); + for (i=0; i<m_page_total_size; i++) + m_data_ptr[m_page_addr*m_page_total_size + i] &= m_pagereg[i]; + m_status |= 0x40; + if (data == 0x15) + m_accumulated_status = m_status & 0x1f; + else + m_accumulated_status = 0; + m_mode = SM_M_INIT; + if (!m_write_rnb.isnull()) + { + m_write_rnb( 0); + m_write_rnb( 1); + } + } + break; + /*case 0x11: + break;*/ + case 0x60: // Block Erase (1st cycle) + m_mode = SM_M_ERASE; + m_page_addr = 0; + m_addr_load_ptr = 0; + break; + case 0xd0: // Block Erase (2nd cycle) + if (m_mode != SM_M_ERASE) + { + logerror("smartmedia: illegal block erase confirm command\n"); + m_mode = SM_M_INIT; + } + else + { + m_status &= 0x80; + memset(m_data_ptr + ((m_page_addr & (-1 << m_log2_pages_per_block)) * m_page_total_size), 0xFF, (size_t)(1 << m_log2_pages_per_block) * m_page_total_size); + //logerror( "smartmedia: erase, page_addr %08X, offset %08X, length %08X\n", m_page_addr, (m_page_addr & (-1 << m_log2_pages_per_block)) * m_page_total_size, (1 << m_log2_pages_per_block) * m_page_total_size); + m_status |= 0x40; + m_mode = SM_M_INIT; + if (m_pointer_mode == SM_PM_B) + m_pointer_mode = SM_PM_A; + if (!m_write_rnb.isnull()) + { + m_write_rnb( 0); + m_write_rnb( 1); + } + } + break; + case 0x70: // Read Status + m_mode = SM_M_READSTATUS; + break; + /*case 0x71: + break;*/ + case 0x90: // Read ID + m_mode = SM_M_READID; + m_addr_load_ptr = 0; + break; + /*case 0x91: + break;*/ + case 0x30: // Read (2nd cycle) + if (m_col_address_cycles == 1) + { + m_mode = SM_M_30; + } + else + { + if (m_mode != SM_M_READ) + { + logerror("smartmedia: illegal read 2nd cycle command\n"); + m_mode = SM_M_INIT; + } + else if (m_addr_load_ptr < (m_col_address_cycles + m_row_address_cycles)) + { + logerror("smartmedia: read 2nd cycle, not enough address cycles (actual: %d, expected: %d)\n", m_addr_load_ptr, m_col_address_cycles + m_row_address_cycles); + m_mode = SM_M_INIT; + } + else + { + if (!m_write_rnb.isnull()) + { + m_write_rnb( 0); + m_write_rnb( 1); + } + } + } + break; + case 0x65: + if (m_mode != SM_M_30) + { + logerror("smartmedia: unexpected address port write\n"); + m_mode = SM_M_INIT; + } + else + { + m_mode_3065 = 1; + } + break; + case 0x05: // Random Data Output (1st cycle) + if ((m_mode != SM_M_READ) && (m_mode != SM_M_RANDOM_DATA_OUTPUT)) + { + logerror("smartmedia: illegal random data output command\n"); + m_mode = SM_M_INIT; + } + else + { + m_mode = SM_M_RANDOM_DATA_OUTPUT; + m_addr_load_ptr = 0; + } + break; + case 0xE0: // Random Data Output (2nd cycle) + if (m_mode != SM_M_RANDOM_DATA_OUTPUT) + { + logerror("smartmedia: illegal random data output confirm command\n"); + m_mode = SM_M_INIT; + } + else + { + // do nothing + } + break; + case 0x85: // Random Data Input + if ((m_mode != SM_M_PROGRAM) && (m_mode != SM_M_RANDOM_DATA_INPUT)) + { + logerror("smartmedia: illegal random data input command\n"); + m_mode = SM_M_INIT; + } + else + { + m_mode = SM_M_RANDOM_DATA_INPUT; + m_addr_load_ptr = 0; + m_program_byte_count = 0; + } + break; + default: + logerror("smartmedia: unsupported command 0x%02x\n", data); + m_mode = SM_M_INIT; + break; + } +} + +/* + write a byte to SmartMedia address port +*/ +void nand_device::address_w(UINT8 data) +{ + if (!is_present()) + return; + + switch (m_mode) + { + case SM_M_INIT: + logerror("smartmedia: unexpected address port write\n"); + break; + case SM_M_READ: + case SM_M_PROGRAM: + if ((m_addr_load_ptr == 0) && (m_col_address_cycles == 1)) + { + switch (m_pointer_mode) + { + case SM_PM_A: + m_byte_addr = data; + break; + case SM_PM_B: + m_byte_addr = data + 256; + m_pointer_mode = SM_PM_A; + break; + case SM_PM_C: + if (!m_mode_3065) + m_byte_addr = (data & 0x0f) + m_page_data_size; + else + m_byte_addr = (data & 0x0f) + 256; + break; + } + } + else + { + if (m_addr_load_ptr < m_col_address_cycles) + { + m_byte_addr &= ~(0xFF << (m_addr_load_ptr * 8)); + m_byte_addr |= (data << (m_addr_load_ptr * 8)); + } + else if (m_addr_load_ptr < m_col_address_cycles + m_row_address_cycles) + { + m_page_addr &= ~(0xFF << ((m_addr_load_ptr - m_col_address_cycles) * 8)); + m_page_addr |= (data << ((m_addr_load_ptr - m_col_address_cycles) * 8)); + } + } + m_addr_load_ptr++; + break; + case SM_M_ERASE: + if (m_addr_load_ptr < m_row_address_cycles) + { + m_page_addr &= ~(0xFF << (m_addr_load_ptr * 8)); + m_page_addr |= (data << (m_addr_load_ptr * 8)); + } + m_addr_load_ptr++; + break; + case SM_M_RANDOM_DATA_INPUT: + case SM_M_RANDOM_DATA_OUTPUT: + if (m_addr_load_ptr < m_col_address_cycles) + { + m_byte_addr &= ~(0xFF << (m_addr_load_ptr * 8)); + m_byte_addr |= (data << (m_addr_load_ptr * 8)); + } + m_addr_load_ptr++; + break; + case SM_M_READSTATUS: + case SM_M_30: + logerror("smartmedia: unexpected address port write\n"); + break; + case SM_M_READID: + if (m_addr_load_ptr == 0) + m_byte_addr = data; + m_addr_load_ptr++; + break; + } +} + +/* + read a byte from SmartMedia data port +*/ +UINT8 nand_device::data_r() +{ + UINT8 reply = 0; + if (!is_present()) + return 0; + + switch (m_mode) + { + case SM_M_INIT: + case SM_M_30: + logerror("smartmedia: unexpected data port read\n"); + break; + case SM_M_READ: + case SM_M_RANDOM_DATA_OUTPUT: + if (!m_mode_3065) + { + if (m_byte_addr < m_page_total_size) + { + reply = m_data_ptr[m_page_addr*m_page_total_size + m_byte_addr]; + } + else + { + reply = 0xFF; + } + } + else + { + reply = m_data_uid_ptr[m_page_addr*m_page_total_size + m_byte_addr]; + } + m_byte_addr++; + if ((m_byte_addr == m_page_total_size) && (m_sequential_row_read != 0)) + { + m_byte_addr = (m_pointer_mode != SM_PM_C) ? 0 : m_page_data_size; + m_page_addr++; + if (m_page_addr == m_num_pages) + m_page_addr = 0; + } + break; + case SM_M_PROGRAM: + case SM_M_RANDOM_DATA_INPUT: + case SM_M_ERASE: + logerror("smartmedia: unexpected data port read\n"); + break; + case SM_M_READSTATUS: + reply = m_status & 0xc1; + break; + case SM_M_READID: + if (m_byte_addr < m_id_len) + reply = m_id[m_byte_addr]; + else + reply = 0; + m_byte_addr++; + break; + } + + return reply; +} + +/* + write a byte to SmartMedia data port +*/ +void nand_device::data_w(UINT8 data) +{ + if (!is_present()) + return; + + switch (m_mode) + { + case SM_M_INIT: + case SM_M_READ: + case SM_M_30: + case SM_M_RANDOM_DATA_OUTPUT: + logerror("smartmedia: unexpected data port write\n"); + break; + case SM_M_PROGRAM: + case SM_M_RANDOM_DATA_INPUT: + if (m_program_byte_count++ < m_page_total_size) + { + m_pagereg[m_byte_addr] = data; + } + m_byte_addr++; + if (m_byte_addr == m_page_total_size) + m_byte_addr = (m_pointer_mode != SM_PM_C) ? 0 : m_page_data_size; + break; + case SM_M_ERASE: + case SM_M_READSTATUS: + case SM_M_READID: + logerror("smartmedia: unexpected data port write\n"); + break; + } +} + + +/* + Initialize one SmartMedia chip: may be called at driver init or image load + time (or machine init time if you don't use MESS image core) +*/ +void nand_device::device_reset() +{ + m_mode = SM_M_INIT; + m_pointer_mode = SM_PM_A; + m_status = (m_status & 0x80) | 0x40; + m_accumulated_status = 0; +} + + +const device_type SMARTMEDIA = &device_creator<smartmedia_image_device>; + +smartmedia_image_device::smartmedia_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nand_device(mconfig, SMARTMEDIA, "SmartMedia Flash ROM", tag, owner, clock, "smartmedia", __FILE__), + device_image_interface(mconfig, *this) +{ +} + +void smartmedia_image_device::device_config_complete() +{ + update_names(); +} diff --git a/src/devices/machine/smartmed.h b/src/devices/machine/smartmed.h new file mode 100644 index 00000000000..15ad48d4235 --- /dev/null +++ b/src/devices/machine/smartmed.h @@ -0,0 +1,237 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +/* + smartmed.h: header file for smartmed.c +*/ + +#ifndef __SMARTMEDIA_H__ +#define __SMARTMEDIA_H__ + +#include "formats/imageutl.h" + +//#define SMARTMEDIA_IMAGE_SAVE + +#define MCFG_NAND_TYPE(_type) \ + nand_device::set_nand_type(*device, _type); + +#define MCFG_NAND_RNB_CALLBACK(_write) \ + devcb = &nand_device::set_rnb_wr_callback(*device, DEVCB_##_write); + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +enum sm_mode_t +{ + SM_M_INIT, // initial state + SM_M_READ, // read page data + SM_M_PROGRAM, // program page data + SM_M_ERASE, // erase block data + SM_M_READSTATUS,// read status + SM_M_READID, // read ID + SM_M_30, + SM_M_RANDOM_DATA_INPUT, + SM_M_RANDOM_DATA_OUTPUT +}; + +enum pointer_sm_mode_t +{ + SM_PM_A, // accessing first 256-byte half of 512-byte data field + SM_PM_B, // accessing second 256-byte half of 512-byte data field + SM_PM_C // accessing spare field +}; + + +// "Sequential Row Read is available only on K9F5608U0D_Y,P,V,F or K9F5608D0D_Y,P" +enum +{ + NAND_CHIP_K9F5608U0D = 0, // K9F5608U0D + NAND_CHIP_K9F5608U0D_J, // K9F5608U0D-Jxxx + NAND_CHIP_K9F5608U0B, // K9F5608U0B + NAND_CHIP_K9F1G08U0B, // K9F1G08U0B + NAND_CHIP_K9LAG08U0M // K9LAG08U0M +}; + +// ======================> nand_device +class nand_device : public device_t +{ +public: + // construction/destruction + nand_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nand_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + template<class _Object> static devcb_base &set_rnb_wr_callback(device_t &device, _Object object) { return downcast<nand_device &>(device).m_write_rnb.set_callback(object); } + + static void set_nand_type(device_t &device, int type) + { + nand_device &dev = downcast<nand_device &>(device); + switch (type) + { + case NAND_CHIP_K9F5608U0D: + dev.m_id_len = 2; + dev.m_id[0] = 0xec; + dev.m_id[1] = 0x75; + dev.m_page_data_size = 512; + dev.m_page_total_size = 512 + 16; + dev.m_log2_pages_per_block = compute_log2(32); + dev.m_num_pages = 32 * 2048; + dev.m_col_address_cycles = 1; + dev.m_row_address_cycles = 2; + dev.m_sequential_row_read = 1; + break; + case NAND_CHIP_K9F5608U0D_J: + case NAND_CHIP_K9F5608U0B: + dev.m_id_len = 2; + dev.m_id[0] = 0xec; + dev.m_id[1] = 0x75; + dev.m_page_data_size = 512; + dev.m_page_total_size = 512 + 16; + dev.m_log2_pages_per_block = compute_log2(32); + dev.m_num_pages = 32 * 2048; + dev.m_col_address_cycles = 1; + dev.m_row_address_cycles = 2; + dev.m_sequential_row_read = 0; + break; + case NAND_CHIP_K9F1G08U0B: + dev.m_id_len = 5; + dev.m_id[0] = 0xec; + dev.m_id[1] = 0xf1; + dev.m_id[2] = 0x00; + dev.m_id[3] = 0x95; + dev.m_id[4] = 0x40; + dev.m_page_data_size = 2048; + dev.m_page_total_size = 2048 + 64; + dev.m_log2_pages_per_block = compute_log2(64); + dev.m_num_pages = 64 * 1024; + dev.m_col_address_cycles = 2; + dev.m_row_address_cycles = 2; + dev.m_sequential_row_read = 0; + break; + case NAND_CHIP_K9LAG08U0M: + dev.m_id_len = 5; + dev.m_id[0] = 0xec; + dev.m_id[1] = 0xd5; + dev.m_id[2] = 0x55; + dev.m_id[3] = 0x25; + dev.m_id[4] = 0x68; + dev.m_page_data_size = 2048; + dev.m_page_total_size = 2048 + 64; + dev.m_log2_pages_per_block = compute_log2(128); + dev.m_num_pages = 128 * 8192; + dev.m_col_address_cycles = 2; + dev.m_row_address_cycles = 3; + dev.m_sequential_row_read = 0; + break; + default: + printf("Unknown NAND type!\n"); + dev.m_id_len = 0; + dev.m_page_data_size = 0; + dev.m_page_total_size = 0; + dev.m_log2_pages_per_block = 0; + dev.m_num_pages = 0; + dev.m_col_address_cycles = 0; + dev.m_row_address_cycles = 0; + dev.m_sequential_row_read = 0; + break; + } + } + + int is_present(); + int is_protected(); + int is_busy(); + + UINT8 data_r(); + void command_w(UINT8 data); + void address_w(UINT8 data); + void data_w(UINT8 data); + + void set_data_ptr(void *ptr); +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + int m_page_data_size; // 256 for a 2MB card, 512 otherwise + int m_page_total_size;// 264 for a 2MB card, 528 otherwise + int m_num_pages; // 8192 for a 4MB card, 16184 for 8MB, 32768 for 16MB, + // 65536 for 32MB, 131072 for 64MB, 262144 for 128MB... + // 0 means no card loaded + int m_log2_pages_per_block; // log2 of number of pages per erase block (usually 4 or 5) + + UINT8* m_data_ptr; // FEEPROM data area + std::unique_ptr<UINT8[]> m_data_uid_ptr; + + sm_mode_t m_mode; // current operation mode + pointer_sm_mode_t m_pointer_mode; // pointer mode + + unsigned int m_page_addr; // page address pointer + int m_byte_addr; // byte address pointer + int m_addr_load_ptr; // address load pointer + + int m_status; // current status + int m_accumulated_status; // accumulated status + + std::unique_ptr<UINT8[]> m_pagereg; // page register used by program command + UINT8 m_id[5]; // chip ID + UINT8 m_mp_opcode; // multi-plane operation code + + int m_mode_3065; + + // Palm Z22 NAND has 512 + 16 byte pages but, for some reason, Palm OS writes 512 + 64 bytes when + // programming a page, so we need to keep track of the number of bytes written so we can ignore the + // last 48 (64 - 16) bytes or else the first 48 bytes get overwritten + int m_program_byte_count; + + int m_id_len; + int m_col_address_cycles; + int m_row_address_cycles; + int m_sequential_row_read; + + devcb_write_line m_write_rnb; + + #ifdef SMARTMEDIA_IMAGE_SAVE + int m_image_format; + #endif +}; + + + +class smartmedia_image_device : public nand_device, + public device_image_interface +{ +public: + // construction/destruction + smartmedia_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // image-level overrides + virtual iodevice_t image_type() const override { return IO_MEMCARD; } + + virtual bool is_readable() const override { return 1; } + virtual bool is_writeable() const override { return 1; } + virtual bool is_creatable() const override { return 0; } + virtual bool must_be_loaded() const override { return 0; } + virtual bool is_reset_on_load() const override { return 0; } + virtual const char *image_interface() const override { return "sm_memc"; } + virtual const char *file_extensions() const override { return "smc"; } + virtual const option_guide *create_option_guide() const override { return nullptr; } + + virtual bool call_load() override; + virtual void call_unload() override; + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) override { return load_software(swlist, swname, start_entry); } + +protected: + // device-level overrides + virtual void device_config_complete() override; + + bool smartmedia_format_1(); + bool smartmedia_format_2(); + int detect_geometry( UINT8 id1, UINT8 id2); +}; + + +// device type definition +extern const device_type NAND; +extern const device_type SMARTMEDIA; + + +#endif /* __SMARTMEDIA_H__ */ |