summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/acorn_bmu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/acorn_bmu.cpp')
-rw-r--r--src/devices/machine/acorn_bmu.cpp267
1 files changed, 267 insertions, 0 deletions
diff --git a/src/devices/machine/acorn_bmu.cpp b/src/devices/machine/acorn_bmu.cpp
new file mode 100644
index 00000000000..94f5e953a53
--- /dev/null
+++ b/src/devices/machine/acorn_bmu.cpp
@@ -0,0 +1,267 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/*********************************************************************
+
+ Acorn Battery Management Unit
+
+ The BMU is actually a 4-bit Hitachi HD404304F MCU, marked as
+ BMU 0290032.
+
+ TODO:
+ - configurable status
+ - callback when battery low
+
+*********************************************************************/
+
+#include "emu.h"
+#include "acorn_bmu.h"
+
+#define LOG_DATA (1U << 1)
+#define LOG_LINE (1U << 2)
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(ACORN_BMU, acorn_bmu_device, "acorn_bmu", "Acorn Battery Management Unit")
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// acorn_bmu_device - constructor
+//-------------------------------------------------
+
+acorn_bmu_device::acorn_bmu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, ACORN_BMU, tag, owner, clock)
+ , m_slave_address(BMU_SLAVE_ADDRESS)
+ , m_scl(0)
+ , m_sdaw(0)
+ , m_sdar(1)
+ , m_state(STATE_IDLE)
+ , m_bits(0)
+ , m_shift(0)
+ , m_devsel(0)
+ , m_register(0)
+ , m_estimate(0)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void acorn_bmu_device::device_start()
+{
+ save_item(NAME(m_scl));
+ save_item(NAME(m_sdaw));
+ save_item(NAME(m_sdar));
+ save_item(NAME(m_state));
+ save_item(NAME(m_bits));
+ save_item(NAME(m_shift));
+ save_item(NAME(m_devsel));
+ save_item(NAME(m_register));
+ save_item(NAME(m_slave_address));
+ save_item(NAME(m_estimate));
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+void acorn_bmu_device::scl_w(int state)
+{
+ if (m_scl != state)
+ {
+ m_scl = state;
+ LOGMASKED(LOG_LINE, "set_scl_line %d\n", m_scl);
+
+ switch (m_state)
+ {
+ case STATE_DEVSEL:
+ case STATE_REGISTER:
+ case STATE_DATAIN:
+ if (m_bits < 8)
+ {
+ if (m_scl)
+ {
+ m_shift = ((m_shift << 1) | m_sdaw) & 0xff;
+ m_bits++;
+ }
+ }
+ else
+ {
+ if (m_scl)
+ {
+ m_bits++;
+ }
+ else
+ {
+ if (m_bits == 8)
+ {
+ switch (m_state)
+ {
+ case STATE_DEVSEL:
+ m_devsel = m_shift;
+
+ if ((m_devsel & 0xfe) != m_slave_address)
+ {
+ LOGMASKED(LOG_DATA, "devsel %02x: not this device\n", m_devsel);
+ m_state = STATE_IDLE;
+ }
+ else if ((m_devsel & 1) == 0)
+ {
+ LOGMASKED(LOG_DATA, "devsel %02x: write\n", m_devsel);
+ m_state = STATE_REGISTER;
+ }
+ else
+ {
+ LOGMASKED(LOG_DATA, "devsel %02x: read\n", m_devsel);
+ m_state = STATE_READSELACK;
+ }
+ break;
+
+ case STATE_REGISTER:
+ m_register = m_shift;
+
+ LOGMASKED(LOG_DATA, "register %02x\n", m_register);
+
+ m_state = STATE_DATAIN;
+ break;
+
+ case STATE_DATAIN:
+ LOGMASKED(LOG_DATA, "register[ %02x ] <- %02x\n", m_register, m_shift);
+
+ switch (m_register)
+ {
+ case BMU_CHARGE_ESTIMATE:
+ m_estimate = m_shift;
+ break;
+ }
+
+ m_register++;
+ break;
+ }
+
+ if( m_state != STATE_IDLE )
+ {
+ m_sdar = 0 ;
+ }
+ }
+ else
+ {
+ m_bits = 0;
+ m_sdar = 1;
+ }
+ }
+ }
+ break;
+
+ case STATE_READSELACK:
+ m_bits = 0;
+ m_state = STATE_DATAOUT;
+ break;
+
+ case STATE_DATAOUT:
+ if (m_bits < 8)
+ {
+ if (m_scl)
+ {
+ m_bits++;
+ }
+ else
+ {
+ if (m_bits == 0)
+ {
+ switch (m_register)
+ {
+ case BMU_VERSION:
+ m_shift = 0x03;
+ break;
+
+ case BMU_STATUS:
+ m_shift = STATUS_CHARGER_PRESENT | STATUS_BATTERY_PRESENT | STATUS_CHARGE_STATE_KNOWN | STATUS_LID_OPEN;
+ break;
+
+ case BMU_CAPACITY_USED:
+ m_shift = 0x40;
+ break;
+
+ case BMU_CHARGE_ESTIMATE:
+ m_shift = m_estimate;
+ break;
+
+ case BMU_COMMAND:
+ m_shift = 0;
+ break;
+ }
+
+ LOGMASKED(LOG_DATA, "register[ %02x ] -> %02x\n", m_register, m_shift);
+ m_register++;
+ }
+
+ m_sdar = (m_shift >> 7) & 1;
+
+ m_shift = (m_shift << 1) & 0xff;
+ }
+ }
+ else
+ {
+ if (m_scl)
+ {
+ if (m_sdaw)
+ {
+ LOGMASKED(LOG_DATA, "nack\n");
+ m_state = STATE_IDLE;
+ }
+
+ m_bits = 0;
+ }
+ else
+ {
+ m_sdar = 1;
+ }
+ }
+ break;
+ }
+ }
+}
+
+void acorn_bmu_device::sda_w(int state)
+{
+ state &= 1;
+ if (m_sdaw != state)
+ {
+ LOGMASKED(LOG_LINE, "set sda %d\n", state);
+ m_sdaw = state;
+
+ if (m_scl)
+ {
+ if (m_sdaw)
+ {
+ LOGMASKED(LOG_DATA, "stop\n");
+ m_state = STATE_IDLE;
+ }
+ else
+ {
+ LOGMASKED(LOG_DATA, "start\n");
+ m_state = STATE_DEVSEL;
+ m_bits = 0;
+ }
+
+ m_sdar = 1;
+ }
+ }
+}
+
+int acorn_bmu_device::sda_r()
+{
+ int res = m_sdar & 1;
+
+ LOGMASKED(LOG_LINE, "read sda %d\n", res);
+
+ return res;
+}