/********************************************************************** DALLAS DS2404 RTC + BACKUP RAM **********************************************************************/ #include "emu.h" #include "ds2404.h" #include #include "devhelpr.h" /*************************************************************************** IMPLEMENTATION ***************************************************************************/ //************************************************************************** // DEVICE CONFIGURATION //************************************************************************** //------------------------------------------------- // ds2404_device_config - constructor //------------------------------------------------- ds2404_device_config::ds2404_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) : device_config(mconfig, static_alloc_device_config, "DS2404", tag, owner, clock), device_config_nvram_interface(mconfig, *this) { } //------------------------------------------------- // static_alloc_device_config - allocate a new // configuration object //------------------------------------------------- device_config *ds2404_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) { return global_alloc(ds2404_device_config(mconfig, tag, owner, clock)); } //------------------------------------------------- // alloc_device - allocate a new device object //------------------------------------------------- device_t *ds2404_device_config::alloc_device(running_machine &machine) const { return auto_alloc(machine, ds2404_device(machine, *this)); } //------------------------------------------------- // static_set_ref_year - configuration helper // to set the reference year //------------------------------------------------- void ds2404_device_config::static_set_ref_year(device_config *device, UINT32 year) { ds2404_device_config *ds2404 = downcast(device); ds2404->m_ref_year = year; } //------------------------------------------------- // static_set_ref_month - configuration helper // to set the reference month //------------------------------------------------- void ds2404_device_config::static_set_ref_month(device_config *device, UINT8 month) { ds2404_device_config *ds2404 = downcast(device); ds2404->m_ref_month = month; } //------------------------------------------------- // static_set_ref_day - configuration helper // to set the reference day //------------------------------------------------- void ds2404_device_config::static_set_ref_day(device_config *device, UINT8 day) { ds2404_device_config *ds2404 = downcast(device); ds2404->m_ref_day = day; } //************************************************************************** // LIVE DEVICE //************************************************************************** const device_type DS2404 = ds2404_device_config::static_alloc_device_config; //------------------------------------------------- // ds2404_device - constructor //------------------------------------------------- ds2404_device::ds2404_device(running_machine &_machine, const ds2404_device_config &config) : device_t(_machine, config), device_nvram_interface(_machine, config, *this), m_config(config) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void ds2404_device::device_start() { struct tm ref_tm; memset(&ref_tm, 0, sizeof(ref_tm)); ref_tm.tm_year = m_config.m_ref_year - 1900; ref_tm.tm_mon = m_config.m_ref_month - 1; ref_tm.tm_mday = m_config.m_ref_day; time_t ref_time = mktime(&ref_tm); time_t current_time; time(¤t_time); current_time -= ref_time; m_rtc[0] = 0x0; m_rtc[1] = (current_time >> 0) & 0xff; m_rtc[2] = (current_time >> 8) & 0xff; m_rtc[3] = (current_time >> 16) & 0xff; m_rtc[4] = (current_time >> 24) & 0xff; emu_timer *timer = m_machine.scheduler().timer_alloc(FUNC(ds2404_tick_callback), (void *)this); timer->adjust(attotime::from_hz(256), 0, attotime::from_hz(256)); } void ds2404_device::ds2404_rom_cmd(UINT8 cmd) { switch(cmd) { case 0xcc: /* Skip ROM */ m_state[0] = DS2404_STATE_COMMAND; m_state_ptr = 0; break; default: fatalerror("DS2404: Unknown ROM command %02X", cmd); break; } } void ds2404_device::ds2404_cmd(UINT8 cmd) { switch(cmd) { case 0x0f: /* Write scratchpad */ m_state[0] = DS2404_STATE_ADDRESS1; m_state[1] = DS2404_STATE_ADDRESS2; m_state[2] = DS2404_STATE_INIT_COMMAND; m_state[3] = DS2404_STATE_WRITE_SCRATCHPAD; m_state_ptr = 0; break; case 0x55: /* Copy scratchpad */ m_state[0] = DS2404_STATE_ADDRESS1; m_state[1] = DS2404_STATE_ADDRESS2; m_state[2] = DS2404_STATE_OFFSET; m_state[3] = DS2404_STATE_INIT_COMMAND; m_state[4] = DS2404_STATE_COPY_SCRATCHPAD; m_state_ptr = 0; break; case 0xf0: /* Read memory */ m_state[0] = DS2404_STATE_ADDRESS1; m_state[1] = DS2404_STATE_ADDRESS2; m_state[2] = DS2404_STATE_INIT_COMMAND; m_state[3] = DS2404_STATE_READ_MEMORY; m_state_ptr = 0; break; default: fatalerror("DS2404: Unknown command %02X", cmd); break; } } UINT8 ds2404_device::ds2404_readmem() { if( m_address < 0x200 ) { return m_sram[ m_address ]; } else if( m_address >= 0x202 && m_address <= 0x206 ) { return m_rtc[ m_address - 0x202 ]; } return 0; } void ds2404_device::ds2404_writemem(UINT8 value) { if( m_address < 0x200 ) { m_sram[ m_address ] = value; } else if( m_address >= 0x202 && m_address <= 0x206 ) { m_rtc[ m_address - 0x202 ] = value; } } WRITE8_DEVICE_HANDLER_TRAMPOLINE(ds2404, ds2404_1w_reset_w) { m_state[0] = DS2404_STATE_IDLE; m_state_ptr = 0; } WRITE8_DEVICE_HANDLER_TRAMPOLINE(ds2404, ds2404_3w_reset_w) { m_state[0] = DS2404_STATE_COMMAND; m_state_ptr = 0; } READ8_DEVICE_HANDLER_TRAMPOLINE(ds2404, ds2404_data_r) { UINT8 value = 0; switch(m_state[m_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(); break; case DS2404_STATE_READ_SCRATCHPAD: if(m_offset < 0x20) { value = m_ram[m_offset]; m_offset++; } break; case DS2404_STATE_WRITE_SCRATCHPAD: break; case DS2404_STATE_COPY_SCRATCHPAD: break; } return value; } WRITE8_DEVICE_HANDLER_TRAMPOLINE(ds2404, ds2404_data_w) { switch( m_state[m_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: m_a1 = data & 0xff; m_state_ptr++; break; case DS2404_STATE_ADDRESS2: m_a2 = data & 0xff; m_state_ptr++; break; case DS2404_STATE_OFFSET: m_end_offset = data & 0xff; m_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( m_offset < 0x20 ) { m_ram[m_offset] = data & 0xff; m_offset++; } else { /* Set OF flag */ } break; case DS2404_STATE_COPY_SCRATCHPAD: break; } if( m_state[m_state_ptr] == DS2404_STATE_INIT_COMMAND ) { switch( m_state[m_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: m_address = (m_a2 << 8) | m_a1; m_address -= 1; break; case DS2404_STATE_WRITE_SCRATCHPAD: m_address = (m_a2 << 8) | m_a1; m_offset = m_address & 0x1f; break; case DS2404_STATE_READ_SCRATCHPAD: m_address = (m_a2 << 8) | m_a1; m_offset = m_address & 0x1f; break; case DS2404_STATE_COPY_SCRATCHPAD: m_address = (m_a2 << 8) | m_a1; for(int i = 0; i <= m_end_offset; i++) { ds2404_writemem(m_ram[i]); m_address++; } break; } m_state_ptr++; } } WRITE8_DEVICE_HANDLER_TRAMPOLINE(ds2404, ds2404_clk_w) { switch( m_state[m_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: m_address++; break; case DS2404_STATE_READ_SCRATCHPAD: break; case DS2404_STATE_WRITE_SCRATCHPAD: break; case DS2404_STATE_COPY_SCRATCHPAD: break; } } TIMER_CALLBACK( ds2404_device::ds2404_tick_callback ) { reinterpret_cast(ptr)->ds2404_tick(); } void ds2404_device::ds2404_tick() { for(int i = 0; i < 5; i++) { m_rtc[ i ]++; if(m_rtc[ i ] != 0) { break; } } } //------------------------------------------------- // nvram_default - called to initialize NVRAM to // its default state //------------------------------------------------- void ds2404_device::nvram_default() { memset(m_sram, 0, sizeof(m_sram)); } //------------------------------------------------- // nvram_read - called to read NVRAM from the // .nv file //------------------------------------------------- void ds2404_device::nvram_read(emu_file &file) { file.read(m_sram, sizeof(m_sram)); } //------------------------------------------------- // nvram_write - called to write NVRAM to the // .nv file //------------------------------------------------- void ds2404_device::nvram_write(emu_file &file) { file.write(m_sram, sizeof(m_sram)); }