summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/ds1994.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/ds1994.cpp')
-rw-r--r--src/devices/machine/ds1994.cpp798
1 files changed, 798 insertions, 0 deletions
diff --git a/src/devices/machine/ds1994.cpp b/src/devices/machine/ds1994.cpp
new file mode 100644
index 00000000000..5d325753b14
--- /dev/null
+++ b/src/devices/machine/ds1994.cpp
@@ -0,0 +1,798 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles, smf, Grull Osgo
+/*
+ * DS1994
+ *
+ * Dallas Semiconductor
+ * 1-Wire Protocol
+ * RTC + BACKUP RAM
+ *
+ */
+
+#include "emu.h"
+#include "machine/ds1994.h"
+
+#include <time.h>
+
+#define VERBOSE_LEVEL 0
+
+inline void ds1994_device::verboselog(int n_level, const char *s_fmt, ...)
+{
+ if ( VERBOSE_LEVEL >= n_level )
+ {
+ va_list v;
+ char buf[32768];
+ va_start(v, s_fmt);
+ vsprintf(buf, s_fmt, v);
+ va_end(v);
+ logerror("ds1994 %s %s: %s", tag(), machine().describe_context(), buf);
+ }
+}
+
+// device type definition
+DEFINE_DEVICE_TYPE(DS1994, ds1994_device, "ds1994", "DS1994 RTC + BACKUP RAM")
+
+ds1994_device::ds1994_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, DS1994, tag, owner, clock), device_nvram_interface(mconfig, *this)
+ , m_timer_main(nullptr)
+ , m_timer_reset(nullptr)
+ , m_timer_clock(nullptr)
+ , m_ref_year(0)
+ , m_ref_month(0)
+ , m_ref_day(0)
+ , m_address(0)
+ , m_offset(0)
+ , m_a1(0)
+ , m_a2(0)
+ , m_bit(0)
+ , m_shift(0)
+ , m_byte(0)
+ , m_rx(false)
+ , m_tx(false)
+ , m_state_ptr(0)
+{
+ memset(m_ram, 0, sizeof(m_ram));
+}
+
+void ds1994_device::device_start()
+{
+ // Reference time setup
+ 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(&current_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;
+
+ // 1-wire timmings
+ t_samp = attotime::from_usec(30);
+ t_rdv = attotime::from_usec(30);
+ t_rstl = attotime::from_usec(480);
+ t_pdh = attotime::from_usec(30);
+ t_pdl = attotime::from_usec(120);
+
+ // 1-wire states
+ m_rx = true;
+ m_tx = true;
+
+ // 1-Wire related
+ save_item(NAME(m_bit));
+ save_item(NAME(m_byte));
+ save_item(NAME(m_shift));
+ save_item(NAME(m_rx));
+ save_item(NAME(m_tx));
+
+ // ds1994 specific
+ save_item(NAME(m_rom));
+ save_item(NAME(m_sram));
+ save_item(NAME(m_ram));
+ save_item(NAME(m_rtc));
+ save_item(NAME(m_address));
+ save_item(NAME(m_a1));
+ save_item(NAME(m_a2));
+ save_item(NAME(m_offset));
+
+ // state machine
+ save_item(NAME(m_state));
+ save_item(NAME(m_state_ptr));
+ for (auto & elem : m_state)
+ elem = STATE_IDLE;
+
+ // timers
+ m_timer_main = timer_alloc(TIMER_MAIN);
+ m_timer_reset = timer_alloc(TIMER_RESET);
+ m_timer_clock = timer_alloc(TIMER_CLOCK);
+
+ m_timer_clock->adjust(attotime::from_hz(256), 0, attotime::from_hz(256));
+}
+
+void ds1994_device::device_reset()
+{
+ m_bit = 0;
+ m_byte = 0;
+ m_shift = 0;
+ m_rx = true;
+ m_tx = true;
+ m_state_ptr = 0;
+ m_state[m_state_ptr] = STATE_IDLE;
+
+ memory_region *region = memregion(DEVICE_SELF);
+ if (region != nullptr)
+ {
+ if (region->bytes() == ROM_SIZE+SPD_SIZE+DATA_SIZE+RTC_SIZE+REGS_SIZE)
+ {
+ memcpy(m_rom, region->base(), ROM_SIZE);
+ memcpy(m_ram , region->base() + ROM_SIZE, SPD_SIZE);
+ memcpy(m_sram, region->base() + ROM_SIZE+SPD_SIZE, DATA_SIZE);
+ memcpy(m_rtc , region->base() + ROM_SIZE+SPD_SIZE+DATA_SIZE, RTC_SIZE);
+ memcpy(m_regs, region->base() + ROM_SIZE+SPD_SIZE+DATA_SIZE+RTC_SIZE, REGS_SIZE);
+ return;
+ }
+ verboselog(0, "ds1994 %s: Wrong region length for data, expected 0x%x, got 0x%x\n", tag(), ROM_SIZE+SPD_SIZE+DATA_SIZE+RTC_SIZE+REGS_SIZE, region->bytes());
+ }
+ else
+ {
+ verboselog(0, "ds1994 %s: Warning, no id provided, answer will be all zeroes.\n", tag());
+ memset(m_rom, 0, ROM_SIZE);
+ memset(m_ram, 0, SPD_SIZE);
+ memset(m_sram, 0, DATA_SIZE);
+ memset(m_rtc, 0, RTC_SIZE);
+ memset(m_regs, 0, REGS_SIZE);
+ }
+}
+
+/********************************************/
+/* */
+/* 1-wire protocol - Tx/Rx Bit Routines */
+/* */
+/********************************************/
+
+bool ds1994_device::one_wire_tx_bit(uint8_t value)
+{
+ if (!m_bit)
+ {
+ m_shift = value;
+ verboselog(1, "one_wire_tx_bit: Byte to send %02x\n", m_shift);
+ }
+ m_tx = m_shift & 1;
+ m_shift >>= 1;
+ verboselog(1, "one_wire_tx_bit: State %d\n", m_tx);
+ m_bit++;
+ if (m_bit == 8) return true;
+ else
+ return false;
+}
+
+bool ds1994_device::one_wire_rx_bit(void)
+{
+ m_shift >>= 1;
+ if (m_rx)
+ {
+ m_shift |= 0x80;
+ }
+ verboselog(1, "one_wire_rx_bit: State %d\n", m_rx);
+ m_bit++;
+ if (m_bit == 8)
+ {
+ verboselog(1, "one_wire_rx_bit: Byte Received %02x\n", m_shift);
+ return true;
+ }
+ else
+ return false;
+}
+
+/********************************************/
+/* */
+/* Internal states - Rom Commands */
+/* */
+/********************************************/
+
+void ds1994_device::ds1994_rom_cmd(void)
+{
+ verboselog(2, "timer_main state_rom_command\n");
+ if (one_wire_rx_bit())
+ {
+ switch (m_shift)
+ {
+ case ROMCMD_READROM:
+ verboselog(1, "timer_main rom_cmd readrom\n");
+ m_bit = 0;
+ m_byte = 0;
+ m_state[0] = STATE_READROM;
+ m_state_ptr = 0;
+ break;
+ case ROMCMD_SKIPROM:
+ verboselog(1, "timer_main rom_cmd skiprom\n");
+ m_bit = 0;
+ m_byte = 0;
+ m_state[0] = STATE_COMMAND;
+ m_state_ptr = 0;
+ break;
+ case ROMCMD_MATCHROM:
+ verboselog(1, "timer_main rom_cmd matchrom\n");
+ m_bit = 0;
+ m_byte = 0;
+ m_state[0] = STATE_MATCHROM;
+ m_state_ptr = 0;
+ break;
+ case ROMCMD_SEARCHROM:
+ case ROMCMD_SEARCHINT:
+ verboselog(0, "timer_main rom_command not implemented %02x\n", m_shift);
+ m_state[m_state_ptr] = STATE_COMMAND;
+ default:
+ verboselog(0, "timer_main rom_command not found %02x\n", m_shift);
+ m_state[m_state_ptr] = STATE_IDLE;
+ break;
+ }
+ }
+}
+
+/********************************************/
+/* */
+/* Internal states - DS1994 Commands */
+/* */
+/********************************************/
+
+void ds1994_device::ds1994_cmd(void)
+{
+ verboselog(2, "timer_main state_command\n");
+ if (one_wire_rx_bit())
+ {
+ switch (m_shift)
+ {
+ case COMMAND_READ_MEMORY:
+ verboselog(1, "timer_main cmd read_memory\n");
+ m_bit = 0;
+ m_byte = 0;
+ m_state[0] = STATE_ADDRESS1;
+ m_state[1] = STATE_ADDRESS2;
+ m_state[2] = STATE_INIT_COMMAND;
+ m_state[3] = STATE_READ_MEMORY;
+ m_state_ptr = 0;
+ break;
+ case COMMAND_WRITE_SCRATCHPAD:
+ verboselog(1, "timer_main cmd write_scratchpad\n");
+ m_bit = 0;
+ m_byte = 0;
+ m_offs_ro = false;
+ m_state[0] = STATE_ADDRESS1;
+ m_state[1] = STATE_ADDRESS2;
+ m_state[2] = STATE_INIT_COMMAND;
+ m_state[3] = STATE_WRITE_SCRATCHPAD;
+ m_state_ptr = 0;
+ break;
+ case COMMAND_READ_SCRATCHPAD:
+ verboselog(1, "timer_main cmd read_scratchpad\n");
+ m_bit = 0;
+ m_byte = 0;
+ m_state[0] = STATE_TXADDRESS1;
+ m_state[1] = STATE_TXADDRESS2;
+ m_state[2] = STATE_TXOFFSET;
+ m_state[3] = STATE_INIT_COMMAND;
+ m_state[4] = STATE_READ_SCRATCHPAD;
+ m_state_ptr = 0;
+ break;
+ case COMMAND_COPY_SCRATCHPAD:
+ verboselog(1, "timer_main cmd copy_scratchpad\n");
+ m_bit = 0;
+ m_byte = 0;
+ m_offs_ro = true;
+ m_auth = true;
+ m_state[0] = STATE_ADDRESS1;
+ m_state[1] = STATE_ADDRESS2;
+ m_state[2] = STATE_OFFSET;
+ m_state[3] = STATE_INIT_COMMAND;
+ m_state[4] = STATE_COPY_SCRATCHPAD;
+ m_state_ptr = 0;
+ break;
+ default:
+ verboselog(0, "timer_main command not handled %02x\n", m_shift);
+ m_state[m_state_ptr] = STATE_IDLE;
+ break;
+ }
+ }
+}
+
+/********************************************/
+/* */
+/* Internal Routines - Memory R/W */
+/* */
+/********************************************/
+
+uint8_t ds1994_device::ds1994_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 ds1994_device::ds1994_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;
+ }
+}
+
+/*************************************************/
+/* */
+/* Internal states - Timer controlled Events */
+/* */
+/*************************************************/
+
+void ds1994_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_CLOCK:
+ for (auto & elem : m_rtc)
+ {
+ elem++;
+ if (elem != 0)
+ {
+ break;
+ }
+ }
+ break;
+ case TIMER_RESET:
+ verboselog(1, "timer_reset\n");
+ m_state[m_state_ptr] = STATE_RESET;
+ m_timer_reset->adjust(attotime::never);
+ break;
+ case TIMER_MAIN:
+ switch (m_state[m_state_ptr])
+ {
+ case STATE_RESET1:
+ verboselog(2, "timer_main state_reset1 %d\n", m_rx);
+ m_tx = false;
+ m_state[m_state_ptr] = STATE_RESET2;
+ m_timer_main->adjust(t_pdl);
+ break;
+ case STATE_RESET2:
+ verboselog(2, "timer_main state_reset2 %d\n", m_rx);
+ m_tx = true;
+ m_bit = 0;
+ m_shift = 0;
+ m_state[m_state_ptr] = STATE_ROMCMD;
+ break;
+ case STATE_ROMCMD:
+ ds1994_rom_cmd();
+ break;
+ case STATE_COMMAND:
+ ds1994_cmd();
+ break;
+ case STATE_MATCHROM:
+ verboselog(2, "timer_main state_matchrom - Data to match: <- %d\n", m_rx);
+ if (one_wire_rx_bit())
+ {
+ if (m_rom[7- m_byte] == m_shift)
+ {
+ m_byte++;
+ m_bit = 0;
+ verboselog(2, "timer_main state_matchrom: datamatch %x - byte=%d\n", m_shift, m_byte);
+ }
+ else
+ {
+ m_state[m_state_ptr] = STATE_IDLE;
+ verboselog(1, "timer_main state_matchrom: no match rx=%x <> mem=%x - byte:%d\n", m_shift, m_rom[7 - m_byte], m_byte);
+ }
+ }
+ if (m_byte == ROM_SIZE)
+ {
+ verboselog(2, "timer_main matchrom finished\n");
+ m_state[m_state_ptr] = STATE_COMMAND;
+ }
+ break;
+ case STATE_ADDRESS1:
+ verboselog(2, "timer_main state_address1\n");
+ if (one_wire_rx_bit())
+ {
+ m_bit = 0;
+ if (m_offs_ro)
+ {
+ if (m_a1 != m_shift) m_auth = false;
+ verboselog(1, "timer_main state_address1 - TA1=%02x - Auth_Code 1=%02x\n", m_a1, m_shift);
+ }
+ else
+ {
+ m_a1 = m_shift & 0xff;
+ verboselog(2, "timer_main state_address1 - Address1=%02x\n", m_a1);
+ }
+ m_state_ptr++;
+ }
+ break;
+ case STATE_ADDRESS2:
+ verboselog(2, "timer_main state_address2\n");
+ if (one_wire_rx_bit())
+ {
+ m_bit = 0;
+ if (m_offs_ro)
+ {
+ if ( m_a2 != m_shift ) m_auth = false;
+ verboselog(1, "timer_main state_address1 - TA2=%02x - Auth_Code 2=%02x\n", m_a1, m_shift);
+ }
+ else
+ {
+ m_a2 = m_shift & 0xff;
+ verboselog(2, "timer_main state_address2 - Address2=%02x\n", m_a2);
+ }
+ m_state_ptr++;
+ }
+ break;
+ case STATE_OFFSET:
+ verboselog(2, "timer_main state_offset\n");
+ if (one_wire_rx_bit())
+ {
+ m_bit = 0;
+ if (m_offs_ro)
+ {
+ if (m_a2 != m_shift) m_auth = false;
+ verboselog(1, "timer_main state_address1 - OFS_ES=%02x - Auth_Code 3=%02x\n", m_offset, m_shift);
+ }
+ else
+ {
+ m_offset = m_shift & 0x1f;
+ verboselog(2, "timer_main state_address2 - Offset=%02x\n", m_offset);
+ }
+ m_state_ptr++;
+ }
+ break;
+ case STATE_WRITE_SCRATCHPAD:
+ verboselog(2, "timer_main state_write_scratchpad\n");
+ if (one_wire_rx_bit())
+ {
+ m_bit = 0;
+ m_ram[m_offset & 0x1f] = m_shift & 0xff;
+ m_offset++;
+ }
+ verboselog(2, "timer_main state_write_scratchpad %d Offs=%02x\n", m_rx, m_offset);
+ break;
+ case STATE_READROM:
+ m_tx = true;
+ if (m_byte == ROM_SIZE)
+ {
+ verboselog(1, "timer_main readrom finished\n");
+ m_state[m_state_ptr] = STATE_COMMAND;
+ }
+ else
+ verboselog(2, "timer_main readrom window closed\n");
+ break;
+ case STATE_TXADDRESS1:
+ m_tx = true;
+ if (m_byte == 1)
+ {
+ verboselog(1, "timer_main txaddress1 finished m_byte=%d\n", m_byte);
+ m_byte = 0;
+ m_state_ptr++;
+ }
+ else
+ verboselog(2, "timer_main txaddress1 window closed\n");
+ break;
+ case STATE_TXADDRESS2:
+ m_tx = true;
+ if (m_byte == 1)
+ {
+ verboselog(1, "timer_main txaddress2 finished m_byte=%d\n", m_byte);
+ m_byte = 0;
+ m_state_ptr++;
+ }
+ else
+ verboselog(2, "timer_main txaddress2 window closed\n");
+ break;
+ case STATE_TXOFFSET:
+ m_tx = true;
+ if (m_byte == 1)
+ {
+ verboselog(1, "timer_main txoffset finished - m_byte=%d\n", m_byte);
+ m_byte = 0;
+ m_state_ptr++;
+ }
+ else
+ verboselog(2, "timer_main txoffset window closed\n");
+ break;
+ case STATE_READ_MEMORY:
+ verboselog(2, "timer_main state_readmemory\n");
+ break;
+ case STATE_COPY_SCRATCHPAD:
+ verboselog(2, "timer_main state_copy_scratchpad\n");
+ break;
+ case STATE_READ_SCRATCHPAD:
+ verboselog(2, "timer_main state_read_scratchpad\n");
+ break;
+ default:
+ verboselog(0, "timer_main state not handled: %d\n", m_state[m_state_ptr]);
+ break;
+ }
+ if (m_state[m_state_ptr] == STATE_INIT_COMMAND)
+ {
+ switch (m_state[m_state_ptr + 1])
+ {
+ case STATE_IDLE:
+ case STATE_COMMAND:
+ case STATE_ADDRESS1:
+ case STATE_ADDRESS2:
+ case STATE_OFFSET:
+ break;
+ case STATE_READ_MEMORY:
+ verboselog(2, "timer_main (init_cmd) -> state_read_memory - set address\n");
+ m_address = (m_a2 << 8) | m_a1;
+ break;
+ case STATE_WRITE_SCRATCHPAD:
+ verboselog(2, "timer_main (init_cmd) -> state_write_scratchpad - set address\n");
+ m_offs_ro = false;
+ m_offset = 0;
+ break;
+ case STATE_READ_SCRATCHPAD:
+ verboselog(2, "timer_main (init_cmd) -> state_read_scratchpad - set address\n");
+ m_address = 0;
+ break;
+ case STATE_COPY_SCRATCHPAD:
+ verboselog(2, "timer_main (init_cmd) -> state_copy_scratchpad - do copy\n");
+ if (m_auth)
+ {
+ m_address = (m_a2 << 8) | m_a1;
+ for (int i = 0; i <= m_offset; i++)
+ {
+ ds1994_writemem(m_ram[i]);
+ m_address++;
+ }
+ }
+ else
+ verboselog(1, "timer_main (init_cmd) -> state_copy_scratchpad - Auth-Rejected\n");
+ break;
+ }
+ m_state_ptr++;
+ }
+ }
+}
+
+/*********************/
+/* */
+/* Write Handler */
+/* */
+/*********************/
+
+WRITE_LINE_MEMBER(ds1994_device::write)
+{
+ verboselog(1, "write(%d)\n", state);
+ if (!state && m_rx)
+ {
+ switch (m_state[m_state_ptr])
+ {
+ case STATE_IDLE:
+ case STATE_INIT_COMMAND:
+ break;
+ case STATE_ROMCMD:
+ verboselog(2, "state_romcommand\n");
+ m_timer_main->adjust(t_samp);
+ break;
+ case STATE_COMMAND:
+ verboselog(2, "state_command\n");
+ m_timer_main->adjust(t_samp);
+ break;
+ case STATE_ADDRESS1:
+ verboselog(2, "state_address1\n");
+ m_timer_main->adjust(t_samp);
+ break;
+ case STATE_ADDRESS2:
+ verboselog(2, "state_address2\n");
+ m_timer_main->adjust(t_samp);
+ break;
+ case STATE_OFFSET:
+ verboselog(2, "state_offset\n");
+ m_timer_main->adjust(t_samp);
+ break;
+ case STATE_TXADDRESS1:
+ verboselog(2, "state_txaddress1\n");
+ if (one_wire_tx_bit(m_a1))
+ {
+ m_bit = 0;
+ m_byte++;
+ }
+ m_timer_main->adjust(t_rdv);
+ break;
+ case STATE_TXADDRESS2:
+ verboselog(2, "state_txaddress2\n");
+ if (one_wire_tx_bit(m_a2))
+ {
+ m_bit = 0;
+ m_byte++;
+ }
+ m_timer_main->adjust(t_rdv);
+ break;
+ case STATE_TXOFFSET:
+ verboselog(2, "state_txoffset\n");
+ if (one_wire_tx_bit(m_offset))
+ {
+ m_bit = 0;
+ m_byte++;
+ }
+ m_timer_main->adjust(t_rdv);
+ break;
+ case STATE_READROM:
+ verboselog(2, "state_readrom\n");
+ if (one_wire_tx_bit(m_rom[7 - m_byte]))
+ {
+ m_bit = 0;
+ m_byte++;
+ }
+ m_timer_main->adjust(t_rdv);
+ break;
+ case STATE_READ_MEMORY:
+ verboselog(2, "state_read_memory\n");
+ if (one_wire_tx_bit(ds1994_readmem()))
+ {
+ m_bit = 0;
+ if ( m_address < DATA_SIZE+RTC_SIZE+REGS_SIZE ) m_address++;
+ else
+ m_tx = true;
+ }
+ m_timer_main->adjust(t_rdv);
+ break;
+ case STATE_MATCHROM:
+ verboselog(2, "state_matchrom\n");
+ m_timer_main->adjust(t_rdv);
+ break;
+ case STATE_COPY_SCRATCHPAD:
+ if ( m_auth )
+ {
+ verboselog(2, "state_copy_scratchpad Auth_Code Match: %d\n", m_tx);
+ m_tx = true;
+ m_auth = false;
+ }
+ else
+ {
+ m_tx = false;
+ verboselog(1, "state_copy_scratchpad Auth_Code No Match: %d\n", m_tx);
+ }
+ m_timer_main->adjust(t_rdv);
+ break;
+ case STATE_WRITE_SCRATCHPAD:
+ verboselog(2, "state_write_scratchpad\n");
+ m_timer_main->adjust(t_samp);
+ break;
+ case STATE_READ_SCRATCHPAD:
+ verboselog(2, "state_read_scratchpad\n");
+ if (one_wire_tx_bit(m_ram[m_address]))
+ {
+ m_bit = 0;
+ if ( m_address <= m_offset ) m_address++;
+ else
+ m_tx = true;
+ }
+ m_timer_main->adjust(t_rdv);
+ break;
+ default:
+ verboselog(0, "state not handled: %d\n", m_state[m_state_ptr]);
+ break;
+ }
+ m_timer_reset->adjust(t_rstl);
+ }
+ else if (state && !m_rx)
+ {
+ switch (m_state[m_state_ptr])
+ {
+ case STATE_RESET:
+ m_state[m_state_ptr] = STATE_RESET1;
+ m_timer_main->adjust(t_pdh);
+ break;
+ }
+ m_timer_reset->adjust(attotime::never);
+ }
+ m_rx = state;
+}
+
+/*********************/
+/* */
+/* Read Handler */
+/* */
+/*********************/
+
+READ_LINE_MEMBER(ds1994_device::read)
+{
+ verboselog(2, "read %d\n", m_tx && m_rx);
+ return m_tx && m_rx;
+}
+
+//-------------------------------------------------
+// nvram_default - called to initialize NVRAM to
+// its default state
+//-------------------------------------------------
+
+void ds1994_device::nvram_default()
+{
+ memset(m_rom, 0, ROM_SIZE);
+ memset(m_ram, 0, SPD_SIZE);
+ memset(m_sram, 0, DATA_SIZE);
+ memset(m_rtc, 0, RTC_SIZE);
+ memset(m_regs, 0, REGS_SIZE);
+}
+
+//-------------------------------------------------
+// nvram_read - called to read NVRAM from the
+// .nv file
+//-------------------------------------------------
+
+void ds1994_device::nvram_read(emu_file &file)
+{
+ file.read(m_rom, ROM_SIZE);
+ file.read(m_ram, SPD_SIZE);
+ file.read(m_sram, DATA_SIZE);
+ file.read(m_rtc, RTC_SIZE);
+ file.read(m_regs, REGS_SIZE);
+}
+
+//-------------------------------------------------
+// nvram_write - called to write NVRAM to the
+// .nv file
+//-------------------------------------------------
+
+void ds1994_device::nvram_write(emu_file &file)
+{
+ file.write(m_rom, ROM_SIZE);
+ file.write(m_ram, SPD_SIZE);
+ file.write(m_sram, DATA_SIZE);
+ file.write(m_rtc, RTC_SIZE);
+ file.write(m_regs, REGS_SIZE);
+}
+
+/*
+
+app74.pdf
+
+Under normal circumstances an ibutton will sample the line 30us after the falling edge of the start condition.
+The internal time base of ibutton may deviate from its nominal value. The allowed tollerance band ranges from 15us to 60us.
+This means that the actual slave sampling may occur anywhere from 15 and 60us after the start condition, which is a ratio of 1 to 4.
+During this time frame the voltage on the data line must stay below Vilmax or above Vihmin.
+
+In the 1-Wire system, the logical values 1 and 0 are represented by certain voltages in special waveforms.
+The waveforms needed to write commands or data to ibuttons are called write-1 and write-0 time slots.
+The duration of a low pulse to write a 1 must be shorter than 15us.
+To write a 0, the duration of the low pulse must be at least 60us to cope with worst-case conditions.
+
+The duration of the active part of a time slot can be extended beyond 60us.
+The maximum extension is limited by the fact that a low pulse of a duration of at least eight active time slots ( 480us ) is defined as a Reset Pulse.
+Allowing the same worst-case tolerance ratio, a low pulse of 120us might be sufficient for a reset.
+This limits the extension of the active part of a time slot to a maximum of 120us to prevent misinterpretation with reset.
+
+Commands and data are sent to ibuttons by combining write-0 and write-1 time slots.
+To read data, the master has to generate read-data time slots to define the start condition of each bit.
+The read-data time slots looks essentially the same as a write-1 time slot from the masters point of view.
+Starting at the high-to-low transition, the ibuttons sends 1 bit of its addressed contents.
+If the data bit is a 1, the ibutton leaves the pulse unchanged.
+If the data bit is a 0, the ibutton will pull the data line low for 15us.
+In this time frame data is valid for reading by the master.
+The duration of the low pulse sent by the master should be a minimum of 1us with a maximum value as short as possible to maximize the master sampling window.
+
+The Reset Pulse provides a clear starting condition that supersedes any time slot synchronisation.
+It is defined as single low pulse of minimum duration of eight time slots or 480us followed by a Reset-high time tRSTH of another 480us.
+After a Reset Pulse has been sent, the ibutton will wait for the time tPDH and then generate a Pulse-Presence Pulse of duration tPDL.
+No other communication on the 1-Wire bus is allowed during tRSTH.
+
+There are 1,000 microseconds in a millisecond, and 1,000 milliseconds in a second.
+Thus, there are 1,000,000 microseconds in a second. Why is it "usec"?
+The "u" is supposed to look like the Greek letter Mu that we use for "micro". .
+*/