diff options
Diffstat (limited to 'src/emu/machine/ds2404.c')
-rw-r--r-- | src/emu/machine/ds2404.c | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/src/emu/machine/ds2404.c b/src/emu/machine/ds2404.c new file mode 100644 index 00000000000..fb4fc09696e --- /dev/null +++ b/src/emu/machine/ds2404.c @@ -0,0 +1,320 @@ +/* Dallas DS2404 RTC/NVRAM */ + +#include "driver.h" +#include "ds2404.h" +#include <time.h> + +typedef enum { + DS2404_STATE_IDLE = 1, /* waiting for ROM command, in 1-wire mode */ + DS2404_STATE_COMMAND, /* waiting for memory command */ + DS2404_STATE_ADDRESS1, /* waiting for address bits 0-7 */ + DS2404_STATE_ADDRESS2, /* waiting for address bits 8-15 */ + DS2404_STATE_OFFSET, /* waiting for ending offset */ + DS2404_STATE_INIT_COMMAND, + DS2404_STATE_READ_MEMORY, /* Read Memory command active */ + DS2404_STATE_WRITE_SCRATCHPAD, /* Write Scratchpad command active */ + DS2404_STATE_READ_SCRATCHPAD, /* Read Scratchpad command active */ + DS2404_STATE_COPY_SCRATCHPAD /* Copy Scratchpad command active */ +} DS2404_STATE; + +typedef struct { + UINT16 address; + UINT16 offset; + UINT16 end_offset; + UINT8 a1, a2; + UINT8 sram[512]; /* 4096 bits */ + UINT8 ram[32]; /* scratchpad ram, 256 bits */ + UINT8 rtc[5]; /* 40-bit RTC counter */ + DS2404_STATE state[8]; + int state_ptr; +} DS2404; + +static DS2404 ds2404; + +static void ds2404_rom_cmd(UINT8 cmd) +{ + switch(cmd) + { + case 0xcc: /* Skip ROM */ + ds2404.state[0] = DS2404_STATE_COMMAND; + ds2404.state_ptr = 0; + break; + + default: + fatalerror("DS2404: Unknown ROM command %02X", cmd); + break; + } +} + +static void ds2404_cmd(UINT8 cmd) +{ + switch(cmd) + { + case 0x0f: /* Write scratchpad */ + ds2404.state[0] = DS2404_STATE_ADDRESS1; + ds2404.state[1] = DS2404_STATE_ADDRESS2; + ds2404.state[2] = DS2404_STATE_INIT_COMMAND; + ds2404.state[3] = DS2404_STATE_WRITE_SCRATCHPAD; + ds2404.state_ptr = 0; + break; + + case 0x55: /* Copy scratchpad */ + ds2404.state[0] = DS2404_STATE_ADDRESS1; + ds2404.state[1] = DS2404_STATE_ADDRESS2; + ds2404.state[2] = DS2404_STATE_OFFSET; + ds2404.state[3] = DS2404_STATE_INIT_COMMAND; + ds2404.state[4] = DS2404_STATE_COPY_SCRATCHPAD; + ds2404.state_ptr = 0; + break; + + case 0xf0: /* Read memory */ + ds2404.state[0] = DS2404_STATE_ADDRESS1; + ds2404.state[1] = DS2404_STATE_ADDRESS2; + ds2404.state[2] = DS2404_STATE_INIT_COMMAND; + ds2404.state[3] = DS2404_STATE_READ_MEMORY; + ds2404.state_ptr = 0; + break; + + default: + fatalerror("DS2404: Unknown command %02X", cmd); + break; + } +} + +static UINT8 ds2404_readmem(void) +{ + if( ds2404.address < 0x200 ) + { + return ds2404.sram[ ds2404.address ]; + } + else if( ds2404.address >= 0x202 && ds2404.address <= 0x206 ) + { + return ds2404.rtc[ ds2404.address - 0x202 ]; + } + return 0; +} + +static void ds2404_writemem(UINT8 value) +{ + if( ds2404.address < 0x200 ) + { + ds2404.sram[ ds2404.address ] = value; + } + else if( ds2404.address >= 0x202 && ds2404.address <= 0x206 ) + { + ds2404.rtc[ ds2404.address - 0x202 ] = value; + } +} + +WRITE8_HANDLER( DS2404_1W_reset_w ) +{ + ds2404.state[0] = DS2404_STATE_IDLE; + ds2404.state_ptr = 0; +} + +WRITE8_HANDLER( DS2404_3W_reset_w ) +{ + ds2404.state[0] = DS2404_STATE_COMMAND; + ds2404.state_ptr = 0; +} + +READ8_HANDLER( DS2404_data_r ) +{ + UINT8 value; + switch( ds2404.state[ds2404.state_ptr] ) + { + case DS2404_STATE_IDLE: + case DS2404_STATE_COMMAND: + case DS2404_STATE_ADDRESS1: + case DS2404_STATE_ADDRESS2: + case DS2404_STATE_OFFSET: + case DS2404_STATE_INIT_COMMAND: + break; + + case DS2404_STATE_READ_MEMORY: + value = ds2404_readmem(); + return value; + + case DS2404_STATE_READ_SCRATCHPAD: + if( ds2404.offset < 0x20 ) { + value = ds2404.ram[ds2404.offset]; + ds2404.offset++; + return value; + } + break; + + case DS2404_STATE_WRITE_SCRATCHPAD: + break; + + case DS2404_STATE_COPY_SCRATCHPAD: + break; + } + return 0; +} + +WRITE8_HANDLER( DS2404_data_w ) +{ + int i; + + switch( ds2404.state[ds2404.state_ptr] ) + { + case DS2404_STATE_IDLE: + ds2404_rom_cmd(data & 0xff); + break; + + case DS2404_STATE_COMMAND: + ds2404_cmd(data & 0xff); + break; + + case DS2404_STATE_ADDRESS1: + ds2404.a1 = data & 0xff; + ds2404.state_ptr++; + break; + + case DS2404_STATE_ADDRESS2: + ds2404.a2 = data & 0xff; + ds2404.state_ptr++; + break; + + case DS2404_STATE_OFFSET: + ds2404.end_offset = data & 0xff; + ds2404.state_ptr++; + break; + + case DS2404_STATE_INIT_COMMAND: + break; + + case DS2404_STATE_READ_MEMORY: + break; + + case DS2404_STATE_READ_SCRATCHPAD: + break; + + case DS2404_STATE_WRITE_SCRATCHPAD: + if( ds2404.offset < 0x20 ) { + ds2404.ram[ds2404.offset] = data & 0xff; + ds2404.offset++; + } else { + /* Set OF flag */ + } + break; + + case DS2404_STATE_COPY_SCRATCHPAD: + break; + } + + if( ds2404.state[ds2404.state_ptr] == DS2404_STATE_INIT_COMMAND ) { + switch( ds2404.state[ds2404.state_ptr+1] ) + { + case DS2404_STATE_IDLE: + case DS2404_STATE_COMMAND: + case DS2404_STATE_ADDRESS1: + case DS2404_STATE_ADDRESS2: + case DS2404_STATE_OFFSET: + case DS2404_STATE_INIT_COMMAND: + break; + + case DS2404_STATE_READ_MEMORY: + ds2404.address = (ds2404.a2 << 8) | ds2404.a1; + ds2404.address -= 1; + break; + + case DS2404_STATE_WRITE_SCRATCHPAD: + ds2404.address = (ds2404.a2 << 8) | ds2404.a1; + ds2404.offset = ds2404.address & 0x1f; + break; + + case DS2404_STATE_READ_SCRATCHPAD: + ds2404.address = (ds2404.a2 << 8) | ds2404.a1; + ds2404.offset = ds2404.address & 0x1f; + break; + + case DS2404_STATE_COPY_SCRATCHPAD: + ds2404.address = (ds2404.a2 << 8) | ds2404.a1; + + for( i=0; i <= ds2404.end_offset; i++ ) { + ds2404_writemem( ds2404.ram[i] ); + ds2404.address++; + } + break; + } + ds2404.state_ptr++; + } +} + +WRITE8_HANDLER( DS2404_clk_w ) +{ + switch( ds2404.state[ds2404.state_ptr] ) + { + case DS2404_STATE_IDLE: + case DS2404_STATE_COMMAND: + case DS2404_STATE_ADDRESS1: + case DS2404_STATE_ADDRESS2: + case DS2404_STATE_OFFSET: + case DS2404_STATE_INIT_COMMAND: + break; + + case DS2404_STATE_READ_MEMORY: + ds2404.address++; + break; + + case DS2404_STATE_READ_SCRATCHPAD: + break; + + case DS2404_STATE_WRITE_SCRATCHPAD: + break; + + case DS2404_STATE_COPY_SCRATCHPAD: + break; + } +} + +static TIMER_CALLBACK( DS2404_tick ) +{ + int i; + for( i = 0; i < 5; i++ ) + { + ds2404.rtc[ i ]++; + if( ds2404.rtc[ i ] != 0 ) + { + break; + } + } +} + +void DS2404_init(int ref_year, int ref_month, int ref_day) +{ + struct tm ref_tm; + time_t ref_time; + time_t current_time; + emu_timer *timer; + + memset( &ref_tm, 0, sizeof( ref_tm ) ); + ref_tm.tm_year = ref_year - 1900; + ref_tm.tm_mon = ref_month - 1; + ref_tm.tm_mday = ref_day; + + ref_time = mktime( &ref_tm ); + + time( ¤t_time ); + current_time -= ref_time; + + ds2404.rtc[ 0 ] = 0x0; + ds2404.rtc[ 1 ] = ( current_time >> 0 ) & 0xff; + ds2404.rtc[ 2 ] = ( current_time >> 8 ) & 0xff; + ds2404.rtc[ 3 ] = ( current_time >> 16 ) & 0xff; + ds2404.rtc[ 4 ] = ( current_time >> 24 ) & 0xff; + + timer = timer_alloc( DS2404_tick ); + timer_adjust( timer, ATTOTIME_IN_HZ( 256 ), 0, ATTOTIME_IN_HZ( 256 ) ); +} + +void DS2404_load(mame_file *file) +{ + mame_fread(file, ds2404.sram, 512); +} + +void DS2404_save(mame_file *file) +{ + mame_fwrite(file, ds2404.sram, 512); +} |