summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/macadb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/macadb.c')
-rw-r--r--src/mame/machine/macadb.c1430
1 files changed, 1430 insertions, 0 deletions
diff --git a/src/mame/machine/macadb.c b/src/mame/machine/macadb.c
new file mode 100644
index 00000000000..76a8a010b57
--- /dev/null
+++ b/src/mame/machine/macadb.c
@@ -0,0 +1,1430 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/***************************************************************************
+
+ macadb.c - handles various aspects of ADB on the Mac.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/mac.h"
+
+#define LOG_ADB 0
+#define LOG_ADB_MCU_CMD 0
+#define LOG_ADB_TALK_LISTEN 0
+
+// ADB states
+#define ADB_STATE_NEW_COMMAND (0)
+#define ADB_STATE_XFER_EVEN (1)
+#define ADB_STATE_XFER_ODD (2)
+#define ADB_STATE_IDLE (3)
+#define ADB_STATE_NOTINIT (4)
+
+// ADB commands
+#define ADB_CMD_RESET (0)
+#define ADB_CMD_FLUSH (1)
+
+// ADB line states
+enum
+{
+ // receive states
+ LST_IDLE = 0,
+ LST_ATTENTION,
+ LST_BIT0,
+ LST_BIT1,
+ LST_BIT2,
+ LST_BIT3,
+ LST_BIT4,
+ LST_BIT5,
+ LST_BIT6,
+ LST_BIT7,
+ LST_TSTOP,
+ LST_WAITT1T,
+ LST_RCVSTARTBIT,
+ LST_SRQNODATA,
+
+ // send states
+ LST_TSTOPSTART,
+ LST_TSTOPSTARTa,
+ LST_STARTBIT,
+ LST_SENDBIT0,
+ LST_SENDBIT0a,
+ LST_SENDBIT1,
+ LST_SENDBIT1a,
+ LST_SENDBIT2,
+ LST_SENDBIT2a,
+ LST_SENDBIT3,
+ LST_SENDBIT3a,
+ LST_SENDBIT4,
+ LST_SENDBIT4a,
+ LST_SENDBIT5,
+ LST_SENDBIT5a,
+ LST_SENDBIT6,
+ LST_SENDBIT6a,
+ LST_SENDBIT7,
+ LST_SENDBIT7a,
+ LST_SENDSTOP,
+ LST_SENDSTOPa
+};
+
+/* *************************************************************************
+ * High-level ADB primitives used by all lower-level implementations
+ * *************************************************************************/
+
+#if LOG_ADB
+static const char *const adb_statenames[4] = { "NEW", "EVEN", "ODD", "IDLE" };
+#endif
+
+int mac_state::adb_pollkbd(int update)
+{
+ int i, j, keybuf, report, codes[2], result;
+ ioport_port *ports[6] = { m_key0, m_key1, m_key2, m_key3, m_key4, m_key5 };
+
+ codes[0] = codes[1] = 0xff; // key up
+ report = result = 0;
+
+ for (i = 0; i < 6; i++)
+ {
+ keybuf = ports[i]->read();
+
+ // any changes in this row?
+ if ((keybuf != m_key_matrix[i]) && (report < 2))
+ {
+ // check each column bit
+ for (j=0; j<16; j++)
+ {
+ if (((keybuf ^ m_key_matrix[i]) >> j) & 1)
+ {
+ // update m_key_matrix
+ if (update)
+ {
+ m_key_matrix[i] = (m_key_matrix[i] & ~ (1 << j)) | (keybuf & (1 << j));
+ }
+
+ codes[report] = (i<<4)|j;
+
+ // key up?
+ if (!(keybuf & (1 << j)))
+ {
+ codes[report] |= 0x80;
+ }
+
+ // update modifier state
+ if (update)
+ {
+ if (((i<<4)|j) == 0x39)
+ {
+ if (codes[report] & 0x80)
+ {
+ m_adb_modifiers &= ~0x20;
+ }
+ else
+ {
+ m_adb_modifiers |= 0x20;
+ }
+ }
+ if (((i<<4)|j) == 0x36)
+ {
+ if (codes[report] & 0x80)
+ {
+ m_adb_modifiers &= ~0x8;
+ }
+ else
+ {
+ m_adb_modifiers |= 0x08;
+ }
+ }
+ if (((i<<4)|j) == 0x38)
+ {
+ if (codes[report] & 0x80)
+ {
+ m_adb_modifiers &= ~0x4;
+ }
+ else
+ {
+ m_adb_modifiers |= 0x04;
+ }
+ }
+ if (((i<<4)|j) == 0x3a)
+ {
+ if (codes[report] & 0x80)
+ {
+ m_adb_modifiers &= ~0x2;
+ }
+ else
+ {
+ m_adb_modifiers |= 0x02;
+ }
+ }
+ if (((i<<4)|j) == 0x37)
+ {
+ if (codes[report] & 0x80)
+ {
+ m_adb_modifiers &= ~0x1;
+ }
+ else
+ {
+ m_adb_modifiers |= 0x01;
+ }
+ }
+ }
+
+ // we run out of keys we can track?
+ report++;
+ if (report == 2)
+ {
+ break;
+ }
+ }
+ }
+
+ // we run out of keys we can track?
+ if (report == 2)
+ {
+ break;
+ }
+ }
+ }
+
+// printf("ADB keyboard: update %d keys %02x %02x\n", update, codes[0], codes[1]);
+
+ // figure out if there was a change
+ if ((m_adb_currentkeys[0] != codes[0]) || (m_adb_currentkeys[1] != codes[1]))
+ {
+ result = 1;
+
+ // if we want to update the current read, do so
+ if (update)
+ {
+ if(m_adb_currentkeys[0] != codes[0]) {
+ m_adb_keybuf[m_adb_keybuf_end] = codes[0];
+ m_adb_keybuf_end = (m_adb_keybuf_end+1) % kADBKeyBufSize;
+ }
+ if(m_adb_currentkeys[1] != codes[1]) {
+ m_adb_keybuf[m_adb_keybuf_end] = codes[1];
+ m_adb_keybuf_end = (m_adb_keybuf_end+1) % kADBKeyBufSize;
+ }
+ m_adb_currentkeys[0] = codes[0];
+ m_adb_currentkeys[1] = codes[1];
+ }
+ }
+
+ return result;
+}
+
+int mac_state::adb_pollmouse()
+{
+ int NewX, NewY, NewButton;
+
+ if (!m_adb_mouse_initialized)
+ {
+ return 0;
+ }
+
+ NewButton = m_mouse0->read() & 0x01;
+ NewX = m_mouse2->read();
+ NewY = m_mouse1->read();
+
+ if ((NewX != m_adb_lastmousex) || (NewY != m_adb_lastmousey) || (NewButton != m_adb_lastbutton))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+void mac_state::adb_accummouse( UINT8 *MouseX, UINT8 *MouseY )
+{
+ int MouseCountX = 0, MouseCountY = 0;
+ int NewX, NewY;
+
+ NewX = ioport("MOUSE2")->read();
+ NewY = ioport("MOUSE1")->read();
+
+ /* see if it moved in the x coord */
+ if (NewX != m_adb_lastmousex)
+ {
+ int diff = NewX - m_adb_lastmousex;
+
+ /* check for wrap */
+ if (diff > 0x80)
+ diff = 0x100-diff;
+ if (diff < -0x80)
+ diff = -0x100-diff;
+
+ MouseCountX += diff;
+ m_adb_lastmousex = NewX;
+ }
+
+ /* see if it moved in the y coord */
+ if (NewY != m_adb_lastmousey)
+ {
+ int diff = NewY - m_adb_lastmousey;
+
+ /* check for wrap */
+ if (diff > 0x80)
+ diff = 0x100-diff;
+ if (diff < -0x80)
+ diff = -0x100-diff;
+
+ MouseCountY += diff;
+ m_adb_lastmousey = NewY;
+ }
+
+ m_adb_lastbutton = m_mouse0->read() & 0x01;
+
+ *MouseX = (UINT8)MouseCountX;
+ *MouseY = (UINT8)MouseCountY;
+}
+
+void mac_state::adb_talk()
+{
+ int addr, reg;
+
+ addr = (m_adb_command>>4);
+ reg = (m_adb_command & 3);
+
+// printf("Mac sent %x (cmd %d addr %d reg %d mr %d kr %d)\n", mac->m_adb_command, (mac->m_adb_command>>2)&3, addr, reg, m_adb_mouseaddr, m_adb_keybaddr);
+
+ if (m_adb_waiting_cmd)
+ {
+ switch ((m_adb_command>>2)&3)
+ {
+ case 0:
+ case 1:
+ switch (reg)
+ {
+ case ADB_CMD_RESET:
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("ADB RESET: reg %x address %x\n", reg, addr);
+ #endif
+ m_adb_direction = 0;
+ m_adb_send = 0;
+ break;
+
+ case ADB_CMD_FLUSH:
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("ADB FLUSH: reg %x address %x\n", reg, addr);
+ #endif
+
+ m_adb_direction = 0;
+ m_adb_send = 0;
+ break;
+
+ default: // reserved/unused
+ break;
+ }
+ break;
+
+ case 2: // listen
+ m_adb_datasize = 0;
+ if ((addr == m_adb_keybaddr) || (addr == m_adb_mouseaddr))
+ {
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("ADB LISTEN: reg %x address %x\n", reg, addr);
+ #endif
+ m_adb_direction = 1; // input from Mac
+ m_adb_command = 0;
+ m_adb_listenreg = reg;
+ m_adb_listenaddr = addr;
+ if ((ADB_IS_EGRET) || (ADB_IS_CUDA))
+ {
+ m_adb_stream_ptr = 0;
+ memset(m_adb_buffer, 0, sizeof(m_adb_buffer));
+ }
+ }
+ else
+ {
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("ADB LISTEN to unknown device, timing out\n");
+ #endif
+ m_adb_direction = 0;
+ }
+ break;
+
+ case 3: // talk
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("ADB TALK: reg %x address %x (K %x M %x)\n", reg, addr, m_adb_keybaddr, m_adb_mouseaddr);
+ #endif
+
+ // keep track of what device the Mac last TALKed to
+ m_adb_last_talk = addr;
+
+ m_adb_direction = 0; // output to Mac
+ if (addr == m_adb_mouseaddr)
+ {
+ UINT8 mouseX, mouseY;
+
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("Talking to mouse, register %x\n", reg);
+ #endif
+
+ switch (reg)
+ {
+ // read mouse
+ case 0:
+ if (m_adb_srq_switch)
+ {
+ m_adb_srq_switch = 0;
+ mouseX = mouseY = 0;
+ }
+ else
+ {
+ this->adb_accummouse(&mouseX, &mouseY);
+ }
+ m_adb_buffer[0] = (m_adb_lastbutton & 0x01) ? 0x00 : 0x80;
+ m_adb_buffer[0] |= mouseX & 0x7f;
+ m_adb_buffer[1] = mouseY & 0x7f;
+ m_adb_datasize = 2;
+ break;
+
+ // get ID/handler
+ case 3:
+ m_adb_buffer[0] = 0x60 | (m_adb_mouseaddr&0xf); // SRQ enable, no exceptional event
+ m_adb_buffer[1] = 0x01; // handler 1
+ m_adb_datasize = 2;
+
+ m_adb_mouse_initialized = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ if (adb_pollkbd(0))
+ {
+ m_adb_srqflag = true;
+ }
+ }
+ else if (addr == m_adb_keybaddr)
+ {
+ int kbd_has_data = 1;
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("Talking to keyboard, register %x\n", reg);
+ #endif
+
+ switch (reg)
+ {
+ // read keyboard
+ case 0:
+ if (m_adb_srq_switch)
+ {
+ m_adb_srq_switch = 0;
+ }
+ else
+ {
+ kbd_has_data = this->adb_pollkbd(1);
+ }
+
+/* if (m_adb_currentkeys[0] != 0xff)
+ {
+ printf("Keys[0] = %02x\n", m_adb_currentkeys[0]);
+ }
+ if (m_adb_currentkeys[1] != 0xff)
+ {
+ printf("Keys[1] = %02x\n", m_adb_currentkeys[1]);
+ }*/
+
+ if(kbd_has_data)
+ {
+ if(m_adb_keybuf_start == m_adb_keybuf_end)
+ {
+ // printf("%s: buffer empty\n", __func__);
+ m_adb_buffer[0] = 0xff;
+ m_adb_buffer[1] = 0xff;
+ }
+ else
+ {
+ m_adb_buffer[1] = m_adb_keybuf[m_adb_keybuf_start];
+ m_adb_keybuf_start = (m_adb_keybuf_start+1) % kADBKeyBufSize;
+ if(m_adb_keybuf_start != m_adb_keybuf_end)
+ {
+ m_adb_buffer[0] = m_adb_keybuf[m_adb_keybuf_start];
+ m_adb_keybuf_start = (m_adb_keybuf_start+1) % kADBKeyBufSize;
+ }
+ else
+ {
+ m_adb_buffer[0] = 0xff;
+ }
+ }
+ m_adb_datasize = 2;
+ }
+ break;
+
+ // read modifier keys
+ case 2:
+ {
+ this->adb_pollkbd(1);
+ m_adb_buffer[0] = m_adb_modifiers;
+ m_adb_buffer[1] = 0xff;
+ m_adb_datasize = 2;
+ }
+ break;
+
+ // get ID/handler
+ case 3:
+ m_adb_buffer[0] = 0x60 | (m_adb_keybaddr&0xf); // SRQ enable, no exceptional event
+ m_adb_buffer[1] = 0x01; // handler 1
+ m_adb_datasize = 2;
+
+ m_adb_keybinitialized = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ if (adb_pollmouse())
+ {
+ m_adb_srqflag = true;
+ }
+ }
+ else
+ {
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("ADB: talking to unconnected device %d (K %d M %d)\n", addr, m_adb_keybaddr, m_adb_mouseaddr);
+ #endif
+ m_adb_buffer[0] = m_adb_buffer[1] = 0;
+ m_adb_datasize = 0;
+
+ if ((adb_pollkbd(0)) || (adb_pollmouse()))
+ {
+ m_adb_srqflag = true;
+ }
+ }
+ break;
+ }
+
+ m_adb_waiting_cmd = 0;
+ }
+ else
+ {
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("Got LISTEN data %02x %02x for device %x reg %x\n", m_adb_command, m_adb_buffer[1], m_adb_listenaddr, m_adb_listenreg);
+ #endif
+
+ m_adb_direction = 0;
+
+ if (m_adb_listenaddr == m_adb_mouseaddr)
+ {
+ if ((m_adb_listenreg == 3) && (m_adb_command > 0) && (m_adb_command < 16))
+ {
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("MOUSE: moving to address %x\n", m_adb_command);
+ #endif
+ m_adb_mouseaddr = m_adb_command&0x0f;
+ }
+ }
+ else if (m_adb_listenaddr == m_adb_keybaddr)
+ {
+ if ((m_adb_listenreg == 3) && (m_adb_command > 0) && (m_adb_command < 16))
+ {
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("KEYBOARD: moving to address %x\n", m_adb_command);
+ #endif
+ m_adb_keybaddr = m_adb_command&0x0f;
+ }
+ }
+ }
+}
+
+TIMER_CALLBACK(mac_adb_tick)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ if ((ADB_IS_EGRET_NONCLASS) || (ADB_IS_CUDA_NONCLASS))
+ {
+ switch (mac->m_adb_linestate)
+ {
+ case LST_SRQNODATA:
+ mac->set_adb_line(ASSERT_LINE);
+ mac->m_adb_linestate = LST_IDLE;
+ break;
+
+ case LST_TSTOPSTART:
+ mac->set_adb_line(ASSERT_LINE);
+ mac->m_adb_timer->adjust(attotime::from_ticks(57, 1000000));
+ mac->m_adb_linestate++;
+ break;
+
+ case LST_TSTOPSTARTa:
+ mac->set_adb_line(CLEAR_LINE);
+ mac->m_adb_timer->adjust(attotime::from_ticks(57, 1000000));
+ mac->m_adb_linestate++;
+ break;
+
+ case LST_STARTBIT:
+ mac->set_adb_line(ASSERT_LINE);
+ mac->m_adb_timer->adjust(attotime::from_ticks(105, 1000000));
+ mac->m_adb_linestate++;
+ break;
+
+ case LST_SENDBIT0:
+ case LST_SENDBIT1:
+ case LST_SENDBIT2:
+ case LST_SENDBIT3:
+ case LST_SENDBIT4:
+ case LST_SENDBIT5:
+ case LST_SENDBIT6:
+ case LST_SENDBIT7:
+ mac->set_adb_line(CLEAR_LINE);
+ if (mac->m_adb_buffer[mac->m_adb_stream_ptr] & 0x80)
+ {
+// printf("1 ");
+ mac->m_adb_timer->adjust(attotime::from_ticks(57, 1000000));
+ }
+ else
+ {
+// printf("0 ");
+ mac->m_adb_timer->adjust(attotime::from_ticks(105, 1000000));
+ }
+ mac->m_adb_linestate++;
+ break;
+
+ case LST_SENDBIT0a:
+ case LST_SENDBIT1a:
+ case LST_SENDBIT2a:
+ case LST_SENDBIT3a:
+ case LST_SENDBIT4a:
+ case LST_SENDBIT5a:
+ case LST_SENDBIT6a:
+ mac->set_adb_line(ASSERT_LINE);
+ if (mac->m_adb_buffer[mac->m_adb_stream_ptr] & 0x80)
+ {
+ mac->m_adb_timer->adjust(attotime::from_ticks(105, 1000000));
+ }
+ else
+ {
+ mac->m_adb_timer->adjust(attotime::from_ticks(57, 1000000));
+ }
+ mac->m_adb_buffer[mac->m_adb_stream_ptr] <<= 1;
+ mac->m_adb_linestate++;
+ break;
+
+ case LST_SENDBIT7a:
+ mac->set_adb_line(ASSERT_LINE);
+ if (mac->m_adb_buffer[mac->m_adb_stream_ptr] & 0x80)
+ {
+// printf(" ");
+ mac->m_adb_timer->adjust(attotime::from_ticks(105, 1000000));
+ }
+ else
+ {
+// printf(" ");
+ mac->m_adb_timer->adjust(attotime::from_ticks(57, 1000000));
+ }
+
+ mac->m_adb_stream_ptr++;
+ if (mac->m_adb_stream_ptr == mac->m_adb_datasize)
+ {
+ mac->m_adb_linestate++;
+ }
+ else
+ {
+ mac->m_adb_linestate = LST_SENDBIT0;
+ }
+ break;
+
+ case LST_SENDSTOP:
+ mac->set_adb_line(CLEAR_LINE);
+ mac->m_adb_timer->adjust(attotime::from_ticks((57*2), 1000000));
+ mac->m_adb_linestate++;
+ break;
+
+ case LST_SENDSTOPa:
+ mac->set_adb_line(ASSERT_LINE);
+ mac->m_adb_timer->adjust(attotime::never);
+ mac->m_adb_linestate = LST_IDLE;
+ break;
+ }
+ }
+ else
+ {
+ // do one clock transition on CB1 to advance the VIA shifter
+ mac->m_adb_extclock ^= 1;
+ mac->m_via1->write_cb1(mac->m_adb_extclock);
+
+ if (mac->m_adb_direction)
+ {
+ mac->m_adb_command <<= 1;
+ }
+ else
+ {
+ mac->m_via1->write_cb2((mac->m_adb_send & 0x80)>>7);
+ mac->m_adb_send <<= 1;
+ }
+
+ mac->m_adb_extclock ^= 1;
+ mac->m_via1->write_cb1(mac->m_adb_extclock);
+
+ mac->m_adb_timer_ticks--;
+ if (!mac->m_adb_timer_ticks)
+ {
+ mac->m_adb_timer->adjust(attotime::never);
+
+ if ((mac->m_adb_direction) && (ADB_IS_BITBANG))
+ {
+ mac->adb_talk();
+ if((mac->m_adb_last_talk == 2) && mac->m_adb_datasize) {
+ mac->m_adb_timer_ticks = 8;
+ mac->m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ }
+ }
+ }
+ else
+ {
+ mac->m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ }
+ }
+}
+
+void mac_state::mac_adb_newaction(int state)
+{
+ if (state != m_adb_state)
+ {
+ #if LOG_ADB
+ printf("New ADB state: %s\n", adb_statenames[state]);
+ #endif
+
+ m_adb_state = state;
+ m_adb_timer_ticks = 8;
+
+ switch (state)
+ {
+ case ADB_STATE_NEW_COMMAND:
+ m_adb_command = m_adb_send = 0;
+ m_adb_direction = 1; // Mac is shifting us a command
+ m_adb_waiting_cmd = 1; // we're going to get a command
+ m_adb_irq_pending = 0;
+ m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ break;
+
+ case ADB_STATE_XFER_EVEN:
+ case ADB_STATE_XFER_ODD:
+ if (m_adb_datasize > 0)
+ {
+ int i;
+
+ // is something trying to send to the Mac?
+ if (m_adb_direction == 0)
+ {
+ // set up the byte
+ m_adb_send = m_adb_buffer[0];
+ m_adb_datasize--;
+
+ // move down the rest of the buffer, if any
+ for (i = 0; i < m_adb_datasize; i++)
+ {
+ m_adb_buffer[i] = m_adb_buffer[i+1];
+ }
+ }
+
+ }
+ else
+ {
+ m_adb_send = 0;
+ m_adb_irq_pending = 1;
+ }
+
+ m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ break;
+
+ case ADB_STATE_IDLE:
+ m_adb_irq_pending = 0;
+ break;
+ }
+ }
+}
+
+TIMER_CALLBACK(mac_pmu_tick)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ // state 10 means this is in response to an ADB command
+ if (mac->m_pm_state == 10)
+ {
+ #if LOG_ADB
+ printf("PM: was state 10, chunk-chunking CB1\n");
+ #endif
+ mac->m_pm_state = 0;
+
+ // tick CB1, which should cause a PMU interrupt on PMU machines
+ mac->m_adb_extclock ^= 1;
+ mac->m_via1->write_cb1(mac->m_adb_extclock);
+ mac->m_adb_extclock ^= 1;
+ mac->m_via1->write_cb1(mac->m_adb_extclock);
+ }
+ else
+ {
+ #if LOG_ADB
+ printf("PM: timer tick, lowering ACK\n");
+ #endif
+ mac->m_pm_ack &= ~2; // lower ACK to handshake next step
+ }
+}
+
+void mac_state::pmu_one_byte_reply(UINT8 result)
+{
+ m_pm_out[0] = m_pm_out[1] = 1; // length
+ m_pm_out[2] = result;
+ m_pm_slen = 3;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+}
+
+void mac_state::pmu_three_byte_reply(UINT8 result1, UINT8 result2, UINT8 result3)
+{
+ m_pm_out[0] = m_pm_out[1] = 3; // length
+ m_pm_out[2] = result1;
+ m_pm_out[3] = result2;
+ m_pm_out[4] = result3;
+ m_pm_slen = 5;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+}
+
+void mac_state::pmu_exec()
+{
+ m_pm_sptr = 0; // clear send pointer
+ m_pm_slen = 0; // and send length
+ m_pm_dptr = 0; // and receive pointer
+
+// printf("PMU: Command %02x\n", mac->m_pm_cmd[0]);
+ switch (m_pm_cmd[0])
+ {
+ case 0x10: // subsystem power and clock ctrl
+ break;
+
+ case 0x20: // send ADB command (PMU must issue an IRQ on completion)
+ #if 0
+ printf("PMU: Send ADB %02x %02x cmd %02x flag %02x data %02x %02x\n",
+ m_pm_cmd[0], // 0x20
+ m_pm_cmd[1], // ???
+ m_pm_cmd[2], // adb flags (2 for autopoll active, 3 to reset bus?)
+ m_pm_cmd[3], // length of ADB data
+ m_pm_cmd[4], // adb data
+ m_pm_cmd[5]);
+ #endif
+
+ #if 0
+ m_pm_state = 10;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ if (ADB_IS_PM_VIA1_CLASS)
+ {
+ m_pmu_int_status = 0x1;
+ }
+ else if (ADB_IS_PM_VIA2_CLASS)
+ {
+ m_pmu_int_status = 0x10;
+ }
+ else
+ {
+ fatalerror("mac: unknown ADB PMU type\n");
+ }
+ m_pmu_last_adb_command = m_pm_cmd[2];
+ m_adb_command = m_pm_cmd[2];
+ m_adb_waiting_cmd = 1;
+ adb_talk();
+
+ if ((m_pm_cmd[2] & 0xf) == 0xb) // LISTEN register 3 (remap)
+ {
+ m_adb_waiting_cmd = 0;
+ m_adb_command = mac->m_pm_cmd[5];
+ adb_talk();
+ }
+ #else
+ if (((m_pm_cmd[2] == 0xfc) || (m_pm_cmd[2] == 0x2c)) && (m_pm_cmd[3] == 4))
+ {
+// printf("PMU: request to poll ADB, returning nothing\n");
+ m_pm_slen = 0;
+ m_pmu_int_status = 0;
+ }
+ else
+ {
+ m_pm_state = 10;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ if (ADB_IS_PM_VIA1_CLASS)
+ {
+ m_pmu_int_status = 0x1;
+ }
+ else if (ADB_IS_PM_VIA2_CLASS)
+ {
+ m_pmu_int_status = 0x10;
+ }
+ else
+ {
+ fatalerror("mac: unknown ADB PMU type\n");
+ }
+ m_pmu_last_adb_command = m_pm_cmd[2];
+ }
+
+ m_adb_command = m_pm_cmd[2];
+ m_adb_waiting_cmd = 1;
+ adb_talk();
+ #endif
+ break;
+
+ case 0x21: // turn ADB auto-poll off (does this need a reply?)
+ break;
+
+ case 0x28: // read ADB
+ if (m_adb_datasize > 0)
+ {
+ m_adb_datasize = 1; // hack
+
+ m_pm_out[0] = m_pm_out[1] = 3 + m_adb_datasize;
+ m_pm_out[2] = 0;
+// m_pm_out[3] = m_pmu_last_adb_command;
+ m_pm_out[3] = 0;
+ m_pm_out[4] = m_adb_datasize;
+ for (int i = 0; i < m_adb_datasize; i++)
+ {
+ m_pm_out[5+i] = 0; //mac->m_adb_buffer[i];
+ }
+ m_pm_slen = 5 + m_adb_datasize;
+ }
+ else
+ {
+ m_pm_out[0] = m_pm_out[1] = 4;
+ m_pm_out[2] = 0;
+ m_pm_out[3] = 0;
+// m_pm_out[3] = m_pmu_last_adb_command;
+ m_pm_out[4] = 1; // length of following data
+ m_pm_out[5] = 0;
+ m_pm_slen = 6;
+ }
+/* printf("ADB packet: ");
+ for (int i = 0; i < m_pm_slen; i++)
+ {
+ printf("%02x ", m_pm_out[i]);
+ }
+ printf("\n");*/
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(1000)));
+ break;
+
+ case 0x31: // write first 20 bytes of PRAM
+ {
+ for (int i = 0; i < 20; i++)
+ {
+ m_adb_pram[i] = m_pm_cmd[1+i];
+ }
+ }
+ break;
+
+ case 0x32: // write extended PRAM byte(s). cmd[2] = address, cmd[3] = length, cmd[4...] = data
+ if ((m_pm_cmd[2] + m_pm_cmd[3]) < 0x100)
+ {
+ int i;
+
+ for (i = 0; i < m_pm_cmd[3]; i++)
+ {
+ m_adb_pram[m_pm_cmd[2] + i] = m_pm_cmd[4+i];
+ }
+ }
+ break;
+
+ case 0x38: // read time
+ {
+ m_pm_out[0] = m_pm_out[1] = 4;
+ m_pm_out[2] = 0x63; // famous Mac RTC value of 8/27/56 8:35:00 PM
+ m_pm_out[3] = 0x0b;
+ m_pm_out[4] = 0xd1;
+ m_pm_out[5] = 0x78;
+ m_pm_slen = 6;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ }
+ break;
+
+ case 0x39: // read first 20 bytes of PRAM
+ {
+ int i;
+
+ m_pm_out[0] = m_pm_out[1] = 20;
+ for (i = 0; i < 20; i++)
+ {
+ m_pm_out[2 + i] = m_adb_pram[i];
+ }
+ m_pm_slen = 22;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ }
+ break;
+
+ case 0x3a: // read extended PRAM byte(s). cmd[2] = address, cmd[3] = length
+ if ((m_pm_cmd[2] + m_pm_cmd[3]) < 0x100)
+ {
+ int i;
+
+ m_pm_out[0] = m_pm_out[1] = m_pm_cmd[3];
+ for (i = 0; i < m_pm_cmd[3]; i++)
+ {
+ m_pm_out[2 + i] = m_adb_pram[m_pm_cmd[2] + i];
+ }
+ m_pm_slen = m_pm_out[0] + 2;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ }
+ break;
+
+ case 0x40: // set screen contrast
+ break;
+
+ case 0x41:
+ break;
+
+ case 0x58: // read internal modem status
+ pmu_one_byte_reply(0);
+ break;
+
+ case 0x60: // set low power warning and cutoff battery levels
+ break;
+
+ case 0x68: // read battery/charger level
+ pmu_three_byte_reply(255, 255, 255);
+ break;
+
+ case 0x69: // read battery/charger instantaneous level and status
+ pmu_three_byte_reply(255, 255, 255);
+ break;
+
+ case 0x6b: // read extended battery/charger level and status (wants an 8 byte reply)
+ m_pm_out[0] = m_pm_out[1] = 8; // length
+ m_pm_out[2] = 255;
+ m_pm_out[3] = 255;
+ m_pm_out[4] = 255;
+ m_pm_out[5] = 255;
+ m_pm_out[6] = 255;
+ m_pm_out[7] = 255;
+ m_pm_out[8] = 255;
+ m_pm_out[9] = 255;
+ m_pm_slen = 10;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ break;
+
+ case 0x6c: // read battery ID
+ pmu_one_byte_reply(1);
+ break;
+
+ case 0x78: // read interrupt flag
+ if (ADB_IS_PM_VIA2_CLASS) // PB 140/170 use a "leaner" PMU protocol where you get the data for a PMU interrupt here
+ {
+ #if 0
+ if ((m_pmu_int_status&0xf0) == 0x10)
+ {
+ if (m_adb_datasize > 0)
+ {
+ m_adb_datasize = 1; // hack
+ m_pm_out[0] = m_pm_out[1] = 2 + m_adb_datasize;
+ m_pm_out[2] = m_pmu_int_status; // ADB status in low nibble
+ m_pm_out[3] = m_pmu_last_adb_command; // ADB command that was sent
+ for (int i = 0; i < m_adb_datasize; i++)
+ {
+ m_pm_out[4+i] = 0; //m_adb_buffer[i];
+ }
+ m_pm_slen = 4 + m_adb_datasize;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(1500)));
+
+/* printf("ADB packet: ");
+ for (int i = 0; i < m_pm_slen; i++)
+ {
+ printf("%02x ", m_pm_out[i]);
+ }
+ printf("\n");*/
+ }
+ else
+ {
+ m_pm_out[0] = m_pm_out[1] = 2;
+ m_pm_out[2] = m_pmu_int_status; // ADB status in low nibble
+ m_pm_out[3] = m_pmu_last_adb_command; // ADB command that was sent OR 0x80 for extra error-ness
+ m_pm_out[4] = 0; // return data
+ m_pm_slen = 4;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(1500)));
+ }
+ }
+ else
+ {
+ pmu_one_byte_reply(mac, m_pmu_int_status);
+ }
+ #else
+ if ((m_pmu_int_status&0xf0) == 0x10)
+ {
+ m_pm_out[0] = m_pm_out[1] = 2;
+ m_pm_out[2] = m_pmu_int_status; // ADB status in low nibble
+ m_pm_out[3] = m_pmu_last_adb_command; // ADB command that was sent OR 0x80 for extra error-ness
+ m_pm_out[4] = 0; // return data
+ m_pm_slen = 4;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(1500)));
+ }
+ else
+ {
+ pmu_one_byte_reply(m_pmu_int_status);
+ }
+ #endif
+ }
+ else
+ {
+ pmu_one_byte_reply(m_pmu_int_status);
+ }
+
+ m_pmu_int_status = 0;
+ break;
+
+ case 0x90: // sound power control
+ break;
+
+ case 0x98: // read sound power state
+ pmu_one_byte_reply(1);
+ break;
+
+ case 0xd8: // read A/D converter (not sure what this does)
+ pmu_one_byte_reply(0);
+ break;
+
+ case 0xe0: // write PMU internal RAM
+ break;
+
+ case 0xe8: // read PMU internal RAM (just return zeroes)
+ {
+ int i;
+
+ m_pm_out[0] = m_pm_out[1] = m_pm_cmd[4];
+// printf("PMU read at %x\n", m_pm_cmd[2] | (m_pm_cmd[3]<<8));
+
+ // note: read at 0xEE00 0 = target disk mode, 0xff = normal bootup
+ // (actually 0x00EE, the 50753 port 6)
+
+ for (i = 0; i < m_pm_cmd[4]; i++)
+ {
+ m_pm_out[2 + i] = 0xff;
+ }
+ m_pm_slen = m_pm_out[0] + 2;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ }
+ break;
+
+ case 0xec: // PMU self-test (send 1 count byte + reply)
+ pmu_one_byte_reply(0);
+ break;
+
+ default:
+ fatalerror("PMU: Unhandled command %02x\n", m_pm_cmd[0]);
+ }
+
+ if (m_pm_slen > 0)
+ {
+ m_pm_state = 1;
+ }
+}
+
+void mac_state::adb_vblank()
+{
+ if ((m_adb_state == ADB_STATE_IDLE) || ((ADB_IS_PM_CLASS) && (m_pmu_poll)))
+ {
+ if (this->adb_pollmouse())
+ {
+ // if the mouse was the last TALK, we can just send the new data
+ // otherwise we need to pull SRQ
+ if ((m_adb_last_talk == m_adb_mouseaddr) && !(ADB_IS_PM_CLASS))
+ {
+ // repeat last TALK to get updated data
+ m_adb_waiting_cmd = 1;
+ this->adb_talk();
+
+ m_adb_timer_ticks = 8;
+ this->m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ }
+ #if 0
+ else if (ADB_IS_PM_CLASS)
+ {
+ m_adb_waiting_cmd = 1;
+ this->adb_talk();
+ m_pm_state = 10;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ if (ADB_IS_PM_VIA1_CLASS)
+ {
+ m_pmu_int_status = 0x1;
+ }
+ else if (ADB_IS_PM_VIA2_CLASS)
+ {
+ m_pmu_int_status = 0x10;
+ }
+ }
+ #endif
+ else
+ {
+ m_adb_irq_pending = 1;
+ m_adb_command = m_adb_send = 0;
+ m_adb_timer_ticks = 1; // one tick should be sufficient to make it see the IRQ
+ this->m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ m_adb_srq_switch = 1;
+ }
+ }
+ else if (this->adb_pollkbd(0))
+ {
+ if ((m_adb_last_talk == m_adb_keybaddr) && !(ADB_IS_PM_CLASS))
+ {
+ // repeat last TALK to get updated data
+ m_adb_waiting_cmd = 1;
+ this->adb_talk();
+
+ m_adb_timer_ticks = 8;
+ this->m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ }
+ #if 0
+ else if (ADB_IS_PM_CLASS)
+ {
+ m_adb_waiting_cmd = 1;
+ this->adb_talk();
+ m_pm_state = 10;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ m_pmu_int_status = 0x1;
+ }
+ #endif
+ else
+ {
+ m_adb_irq_pending = 1;
+ m_adb_command = m_adb_send = 0;
+ m_adb_timer_ticks = 1; // one tick should be sufficient to make it see the IRQ
+ this->m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ m_adb_srq_switch = 1;
+ }
+ }
+ }
+}
+
+void mac_state::adb_reset()
+{
+ int i;
+
+ m_adb_srq_switch = 0;
+ m_adb_irq_pending = 0; // no interrupt
+ m_adb_timer_ticks = 0;
+ m_adb_command = 0;
+ m_adb_extclock = 0;
+ m_adb_send = 0;
+ m_adb_waiting_cmd = 0;
+ m_adb_streaming = MCU_STREAMING_NONE;
+ m_adb_state = 0;
+ m_adb_srqflag = false;
+ m_pmu_poll = 0;
+ if (ADB_IS_BITBANG_CLASS)
+ {
+ m_adb_state = ADB_STATE_NOTINIT;
+ }
+ m_adb_direction = 0;
+ m_adb_datasize = 0;
+ m_adb_last_talk = -1;
+
+ m_adb_linestate = 0;
+
+ // mouse
+ m_adb_mouseaddr = 3;
+ m_adb_lastmousex = m_adb_lastmousey = m_adb_lastbutton = 0;
+ m_adb_mouse_initialized = 0;
+
+ // keyboard
+ m_adb_keybaddr = 2;
+ m_adb_keybinitialized = 0;
+ m_adb_currentkeys[0] = m_adb_currentkeys[1] = 0xff;
+ m_adb_modifiers = 0xff;
+ for (i=0; i<7; i++)
+ {
+ m_key_matrix[i] = 0;
+ }
+ m_adb_keybuf_start = 0;
+ m_adb_keybuf_end = 0;
+}
+
+WRITE_LINE_MEMBER(mac_state::adb_linechange_w)
+{
+ int dtime = 0;
+/* static const char *states[] =
+ {
+ "idle",
+ "attention",
+ "bit0",
+ "bit1",
+ "bit2",
+ "bit3",
+ "bit4",
+ "bit5",
+ "bit6",
+ "bit7",
+ "tstop",
+ "waitt1t",
+ "rcvstartbit",
+ "srqnodata"
+ };*/
+
+ if (ADB_IS_EGRET)
+ {
+ dtime = m_egret->get_adb_dtime();
+ }
+ else if (ADB_IS_CUDA)
+ {
+ dtime = m_cuda->get_adb_dtime();
+ }
+
+/* if (m_adb_linestate <= 12)
+ {
+ printf("linechange: %d -> %d, time %d (state %d = %s)\n", state^1, state, dtime, m_adb_linestate, states[m_adb_linestate]);
+ }
+ else
+ {
+ printf("linechange: %d -> %d, time %d (state %d)\n", state^1, state, dtime, m_adb_linestate);
+ }*/
+
+ if ((m_adb_direction) && (m_adb_linestate == LST_TSTOP))
+ {
+ if (m_adb_stream_ptr & 1) // odd byte, can't end here
+ {
+// printf("critical linechange: odd, cont\n");
+ m_adb_linestate = LST_BIT0;
+ }
+ else
+ {
+ if (dtime < 90)
+ {
+// printf("critical linechange: even, and it's another bit\n");
+ m_adb_linestate = LST_BIT0;
+ }
+ }
+ }
+
+ switch (m_adb_linestate)
+ {
+ case LST_IDLE:
+ if ((state) && (dtime >= 4500)) // reset
+ {
+// printf("ADB RESET\n");
+ }
+ else if ((state) && (dtime >= 1200)) // attention
+ {
+// printf("ADB ATTENTION\n");
+ m_adb_waiting_cmd = 1;
+ m_adb_direction = 0;
+ m_adb_linestate++;
+ }
+ break;
+
+ case LST_ATTENTION:
+ if ((!state) && (dtime >= 90)) // Tsync
+ {
+// printf("ADB Tsync\n");
+ m_adb_command = 0;
+ m_adb_linestate++;
+ }
+ break;
+
+ case LST_BIT0:
+ case LST_BIT1:
+ case LST_BIT2:
+ case LST_BIT3:
+ case LST_BIT4:
+ case LST_BIT5:
+ case LST_BIT6:
+ case LST_BIT7:
+ if (!state)
+ {
+ if (dtime >= 90) // "1" bit
+ {
+ m_adb_command |= 1;
+ }
+// printf("ADB bit %d\n", m_adb_command & 1);
+
+ if (m_adb_linestate != LST_BIT7)
+ {
+ m_adb_command <<= 1;
+ }
+ else
+ {
+ if (m_adb_direction)
+ {
+// printf("listen byte[%d] = %02x\n", m_adb_stream_ptr, m_adb_command);
+ m_adb_buffer[m_adb_stream_ptr++] = m_adb_command;
+ m_adb_command = 0;
+ }
+ }
+
+ m_adb_linestate++;
+ }
+ break;
+
+ case LST_TSTOP:
+ if (state)
+ {
+// printf("ADB TSTOP, command byte %02x\n", m_adb_command);
+
+ if (m_adb_direction)
+ {
+ m_adb_command = m_adb_buffer[0];
+ }
+
+ m_adb_srqflag = false;
+ adb_talk();
+
+ if (!m_adb_srqflag)
+ {
+ set_adb_line(ASSERT_LINE);
+ }
+ else
+ {
+ set_adb_line(CLEAR_LINE);
+ }
+
+ if (m_adb_datasize > 0)
+ {
+/* printf("Device has %d bytes of data: ", m_adb_datasize);
+ for (int i = 0; i < m_adb_datasize; i++)
+ {
+ printf("%02x ", m_adb_buffer[i]);
+ }*/
+ m_adb_linestate = LST_TSTOPSTART; // T1t
+ m_adb_timer->adjust(attotime::from_ticks(324/4, 1000000));
+ m_adb_stream_ptr = 0;
+ }
+ else if (m_adb_direction) // if direction is set, we LISTENed to a valid device
+ {
+ m_adb_linestate = LST_WAITT1T;
+ }
+ else // no valid device targetted, time out
+ {
+ if (m_adb_srqflag)
+ {
+ m_adb_linestate = LST_SRQNODATA;
+ m_adb_timer->adjust(attotime::from_ticks(486, 1000000)); // SRQ time
+ }
+ else
+ {
+ m_adb_linestate = LST_IDLE;
+ }
+ }
+ }
+ break;
+
+ case LST_WAITT1T:
+ if ((!state) && (dtime >= 300)) // T1t
+ {
+// printf("ADB T1t\n");
+ m_adb_linestate++;
+ }
+ break;
+
+ case LST_RCVSTARTBIT:
+ if ((!state) && (dtime >= 90)) // start
+ {
+// printf("ADB start\n");
+ m_adb_linestate = LST_BIT0;
+ m_adb_command = 0;
+ }
+ break;
+ }
+}
+
+void mac_state::set_adb_line(int linestate)
+{
+ if (ADB_IS_EGRET)
+ {
+ m_egret->set_adb_line(linestate);
+ }
+ else if (ADB_IS_CUDA)
+ {
+ m_cuda->set_adb_line(linestate);
+ }
+}