// license:BSD-3-Clause // copyright-holders:Aaron Giles /********************************************************************** DALLAS DS2404 RTC + BACKUP RAM **********************************************************************/ #include "emu.h" #include "ds2404.h" #include #include // FIXME: re-write in terms of device_rtc_interface and remove this //************************************************************************** // LIVE DEVICE //************************************************************************** // device type definition DEFINE_DEVICE_TYPE(DS2404, ds2404_device, "ds2404", "DS2404 EconoRAM Time Chip") //------------------------------------------------- // ds2404_device - constructor //------------------------------------------------- ds2404_device::ds2404_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, DS2404, tag, owner, clock), device_nvram_interface(mconfig, *this), m_tick_timer(nullptr), m_ref_year(0), m_ref_month(0), m_ref_day(0), m_address(0), m_offset(0), m_end_offset(0), m_a1(0), m_a2(0), m_state_ptr(0) { std::fill(std::begin(m_ram), std::end(m_ram), 0); } //------------------------------------------------- // 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_ref_year - 1900; ref_tm.tm_mon = m_ref_month - 1; ref_tm.tm_mday = 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; for (auto & elem : m_state) elem = DS2404_STATE_IDLE; m_tick_timer = timer_alloc(0); m_tick_timer->adjust(attotime::from_hz(256), 0, attotime::from_hz(256)); } void ds2404_device::ds2404_rom_cmd(uint8_t 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\n", cmd); } } void ds2404_device::ds2404_cmd(uint8_t 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\n", cmd); } } uint8_t 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_t 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_MEMBER( ds2404_device::ds2404_1w_reset_w ) { m_state[0] = DS2404_STATE_IDLE; m_state_ptr = 0; } WRITE8_MEMBER( ds2404_device::ds2404_3w_reset_w ) { m_state[0] = DS2404_STATE_COMMAND; m_state_ptr = 0; } READ8_MEMBER( ds2404_device::ds2404_data_r ) { uint8_t 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_MEMBER( ds2404_device::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_MEMBER( ds2404_device::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; } } void ds2404_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { switch(id) { case 0: // tick for(auto &elem : m_rtc) { elem++; if(elem != 0) break; } break; default: throw emu_fatalerror("Unknown id in ds2404_device::device_timer"); } } //------------------------------------------------- // 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)); }