mirror of
https://github.com/holub/mame
synced 2025-06-01 02:21:48 +03:00
807 lines
19 KiB
C
807 lines
19 KiB
C
/*
|
|
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"
|
|
|
|
#include "harddisk.h"
|
|
#include "imagedev/harddriv.h"
|
|
#include "formats/imageutl.h"
|
|
|
|
#define MAX_SMARTMEDIA 1
|
|
|
|
/* machine-independent big-endian 32-bit integer */
|
|
struct UINT32BE
|
|
{
|
|
UINT8 bytes[4];
|
|
};
|
|
|
|
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
|
|
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 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(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__)
|
|
{
|
|
}
|
|
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)
|
|
{
|
|
}
|
|
|
|
void nand_device::device_config_complete()
|
|
{
|
|
// inherit a copy of the static data
|
|
const nand_interface *intf = reinterpret_cast<const nand_interface *>(static_config());
|
|
if (intf != NULL)
|
|
{
|
|
*static_cast<nand_interface *>(this) = *intf;
|
|
m_id_len = m_chip.id_len;
|
|
memcpy( m_id, m_chip.id, m_chip.id_len);
|
|
m_page_data_size = m_chip.page_size;
|
|
m_page_total_size = m_chip.page_size + m_chip.oob_size;
|
|
m_log2_pages_per_block = compute_log2( m_chip.pages_per_block);
|
|
m_num_pages = m_chip.pages_per_block * m_chip.blocks_per_device;
|
|
m_col_address_cycles = m_chip.col_address_cycles;
|
|
m_row_address_cycles = m_chip.row_address_cycles;
|
|
m_sequential_row_read = m_chip.sequential_row_read;
|
|
}
|
|
|
|
// or initialize to defaults if none provided
|
|
else
|
|
{
|
|
memset(&m_chip, 0, sizeof(m_chip));
|
|
memset(&m_devcb_write_line_cb, 0, sizeof(m_devcb_write_line_cb));
|
|
m_id_len = 0;
|
|
m_page_data_size = 0;
|
|
m_page_total_size = 0;
|
|
m_log2_pages_per_block = 0;
|
|
m_num_pages = 0;
|
|
m_pagereg = NULL;
|
|
m_col_address_cycles = 0;
|
|
m_row_address_cycles = 0;
|
|
m_sequential_row_read = 0;
|
|
}
|
|
}
|
|
/*
|
|
Init a SmartMedia image
|
|
*/
|
|
void nand_device::device_start()
|
|
{
|
|
m_data_ptr = NULL;
|
|
m_data_uid_ptr = NULL;
|
|
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 = auto_alloc_array(machine(), UINT8, m_page_total_size);
|
|
|
|
#ifdef SMARTMEDIA_IMAGE_SAVE
|
|
m_image_format = 0;
|
|
#endif
|
|
m_devcb_write_line_rnb.resolve( m_devcb_write_line_cb, *this);
|
|
}
|
|
|
|
/*
|
|
Load a SmartMedia image
|
|
*/
|
|
bool smartmedia_image_device::smartmedia_format_1()
|
|
{
|
|
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 = auto_alloc_array(machine(), 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 = auto_alloc_array(machine(), 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, 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 = auto_alloc_array(machine(), 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 = auto_alloc_array(machine(), 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 + 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 + 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)
|
|
{
|
|
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 = NULL;
|
|
m_data_uid_ptr = NULL;
|
|
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 = auto_alloc_array(machine(), 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_devcb_write_line_rnb.isnull())
|
|
{
|
|
m_devcb_write_line_rnb( 0);
|
|
m_devcb_write_line_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, 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_devcb_write_line_rnb.isnull())
|
|
{
|
|
m_devcb_write_line_rnb( 0);
|
|
m_devcb_write_line_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_devcb_write_line_rnb.isnull())
|
|
{
|
|
m_devcb_write_line_rnb( 0);
|
|
m_devcb_write_line_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_devcb_write_line_rnb.isnull())
|
|
{
|
|
m_devcb_write_line_rnb( 0);
|
|
m_devcb_write_line_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),
|
|
m_image_interface(NULL)
|
|
{
|
|
}
|
|
|
|
void smartmedia_image_device::device_config_complete()
|
|
{
|
|
nand_device::device_config_complete();
|
|
update_names();
|
|
}
|