summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/machine/ds2401.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/machine/ds2401.c')
-rw-r--r--trunk/src/emu/machine/ds2401.c239
1 files changed, 239 insertions, 0 deletions
diff --git a/trunk/src/emu/machine/ds2401.c b/trunk/src/emu/machine/ds2401.c
new file mode 100644
index 00000000000..f0e9e5ce33c
--- /dev/null
+++ b/trunk/src/emu/machine/ds2401.c
@@ -0,0 +1,239 @@
+/*
+ * DS2401
+ *
+ * Dallas Semiconductor
+ * Silicon Serial Number
+ *
+ */
+
+#include "emu.h"
+#include "machine/ds2401.h"
+
+#define VERBOSE_LEVEL 0
+
+inline void ATTR_PRINTF(3,4) ds2401_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("ds2401 %s %s: %s", tag(), machine().describe_context(), buf);
+ }
+}
+
+// device type definition
+const device_type DS2401 = &device_creator<ds2401_device>;
+
+ds2401_device::ds2401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, DS2401, "DS2401", tag, owner, clock)
+{
+}
+
+void ds2401_device::device_start()
+{
+ 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);
+
+ save_item(NAME(state));
+ save_item(NAME(bit));
+ save_item(NAME(byte));
+ save_item(NAME(shift));
+ save_item(NAME(rx));
+ save_item(NAME(tx));
+
+ timer_main = timer_alloc(TIMER_MAIN);
+ timer_reset = timer_alloc(TIMER_RESET);
+}
+
+void ds2401_device::device_reset()
+{
+ state = STATE_IDLE;
+ bit = 0;
+ byte = 0;
+ shift = 0;
+ rx = true;
+ tx = true;
+
+ if(m_region)
+ {
+ // Ensure the size is correct though
+ if(m_region->bytes() != SIZE_DATA)
+ logerror("ds2401 %s: Wrong region length for id data, expected 0x%x, got 0x%x\n",
+ tag(),
+ SIZE_DATA,
+ m_region->bytes());
+ else {
+ UINT8 *rb = m_region->base();
+ memcpy(data, rb, SIZE_DATA);
+ return;
+ }
+ }
+
+ // That chip is useless without an id, so bitch if there
+ // isn't one
+ logerror("ds2401 %s: Warning, no id provided, answer will be all zeroes.\n", tag());
+ memset(data, 0, SIZE_DATA);
+}
+
+void ds2401_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id) {
+ case TIMER_RESET:
+ verboselog(1, "timer_reset\n");
+ state = STATE_RESET;
+ timer_reset->adjust(attotime::never);
+ break;
+
+ case TIMER_MAIN:
+ switch(state) {
+ case STATE_RESET1:
+ verboselog(2, "timer_main state_reset1 %d\n", rx);
+ tx = false;
+ state = STATE_RESET2;
+ timer_main->adjust(t_pdl);
+ break;
+
+ case STATE_RESET2:
+ verboselog(2, "timer_main state_reset2 %d\n", rx);
+ tx = true;
+ bit = 0;
+ shift = 0;
+ state = STATE_COMMAND;
+ break;
+
+ case STATE_COMMAND:
+ verboselog(2, "timer_main state_command %d\n", rx);
+ shift >>= 1;
+ if(rx)
+ shift |= 0x80;
+ bit++;
+ if(bit == 8) {
+ switch(shift) {
+ case COMMAND_READROM:
+ verboselog(1, "timer_main readrom\n");
+ bit = 0;
+ byte = 0;
+ state = STATE_READROM;
+ break;
+ default:
+ verboselog(0, "timer_main command not handled %02x\n", shift);
+ state = STATE_IDLE;
+ break;
+ }
+ }
+ break;
+
+ case STATE_READROM:
+ tx = true;
+ if(byte == SIZE_DATA) {
+ verboselog(1, "timer_main readrom finished\n");
+ state = STATE_IDLE;
+ } else {
+ verboselog(2, "timer_main readrom window closed\n");
+ }
+ break;
+ default:
+ verboselog(0, "timer_main state not handled: %d\n", state);
+ break;
+ }
+ }
+}
+
+void ds2401_device::write(bool line)
+{
+ verboselog(1, "write(%d)\n", line);
+
+ if(!line && rx) {
+ switch(state) {
+ case STATE_IDLE:
+ break;
+ case STATE_COMMAND:
+ verboselog(2, "state_command\n");
+ timer_main->adjust(t_samp);
+ break;
+ case STATE_READROM:
+ if(!bit) {
+ shift = data[7 - byte];
+ verboselog(1, "<- data %02x\n", shift);
+ }
+ tx = shift & 1;
+ shift >>= 1;
+ bit++;
+ if(bit == 8) {
+ bit = 0;
+ byte++;
+ }
+ verboselog(2, "state_readrom %d\n", tx);
+ timer_main->adjust(t_rdv);
+ break;
+ default:
+ verboselog(0, "state not handled: %d\n", state );
+ break;
+ }
+ timer_reset->adjust(t_rstl);
+ } else if(line && !rx) {
+ switch(state) {
+ case STATE_RESET:
+ state = STATE_RESET1;
+ timer_main->adjust(t_pdh);
+ break;
+ }
+ timer_reset->adjust(attotime::never);
+ }
+ rx = line;
+}
+
+bool ds2401_device::read()
+{
+ verboselog(2, "read %d\n", tx && rx);
+ return tx && rx;
+}
+
+UINT8 ds2401_device::direct_read(int index)
+{
+ return data[index];
+}
+
+/*
+
+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". .
+*/