summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/1mb5.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/1mb5.cpp')
-rw-r--r--src/devices/machine/1mb5.cpp295
1 files changed, 295 insertions, 0 deletions
diff --git a/src/devices/machine/1mb5.cpp b/src/devices/machine/1mb5.cpp
new file mode 100644
index 00000000000..0aa151251d2
--- /dev/null
+++ b/src/devices/machine/1mb5.cpp
@@ -0,0 +1,295 @@
+// license:BSD-3-Clause
+// copyright-holders:F. Ulivi
+/*********************************************************************
+
+ 1mb5.cpp
+
+ HP-8x I/O Translator chip (1MB5-0101)
+
+ Reference for this chip:
+ HP, aug 79, 1MB5 Detailed specification - Translator chip
+
+*********************************************************************/
+
+#include "emu.h"
+#include "1mb5.h"
+
+// Debugging
+#define VERBOSE 0
+#include "logmacro.h"
+
+// device type definition
+DEFINE_DEVICE_TYPE(HP_1MB5, hp_1mb5_device, "hp_1mb5", "HP 1MB5")
+
+// Bit manipulation
+namespace {
+ static constexpr unsigned BIT_MASK(unsigned n)
+ {
+ return 1U << n;
+ }
+
+ template<typename T> void BIT_CLR(T& w , unsigned n)
+ {
+ w &= ~(T)BIT_MASK(n);
+ }
+
+ template<typename T> void BIT_SET(T& w , unsigned n)
+ {
+ w |= (T)BIT_MASK(n);
+ }
+
+ template<typename T> void COPY_BIT(bool bit , T& w , unsigned n)
+ {
+ if (bit) {
+ BIT_SET(w , n);
+ } else {
+ BIT_CLR(w , n);
+ }
+ }
+}
+
+hp_1mb5_device::hp_1mb5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+: device_t(mconfig , HP_1MB5 , tag , owner , clock),
+ m_irl_handler(*this),
+ m_halt_handler(*this),
+ m_reset_handler(*this),
+ m_int_handler(*this)
+{
+}
+
+READ8_MEMBER(hp_1mb5_device::cpu_r)
+{
+ uint8_t res = 0;
+
+ switch (offset) {
+ case 0:
+ // Read SR
+ res = m_sr & 0x7e;
+ if (m_obf) {
+ BIT_SET(res , 7);
+ }
+ if (m_ibf) {
+ BIT_SET(res , 0);
+ }
+ break;
+
+ case 1:
+ // Read IB
+ res = m_ib;
+ m_ibf = false;
+ update_halt();
+ break;
+ }
+
+ //LOG("RD %u=%02x\n" , offset , res);
+ return res;
+}
+
+WRITE8_MEMBER(hp_1mb5_device::cpu_w)
+{
+ //LOG("WR %u=%02x\n" , offset , data);
+ bool need_resched = false;
+
+ switch (offset) {
+ case 0:
+ // Write CR
+ m_cr = data;
+ need_resched |= set_reset(BIT(m_cr , 7));
+ need_resched |= set_int(!BIT(m_cr , 0));
+ break;
+
+ case 1:
+ // Write OB
+ m_ob = data;
+ m_obf = true;
+ update_halt();
+ break;
+ }
+ if (need_resched) {
+ LOG("resched %s\n" , space.device().tag());
+ space.device().execute().yield();
+ }
+}
+
+READ8_MEMBER(hp_1mb5_device::uc_r)
+{
+ uint8_t res = 0;
+ bool need_resched = false;
+
+ switch (offset) {
+ case 0:
+ // Read CR
+ res = m_cr & 0x7e;
+ if (m_obf) {
+ BIT_SET(res , 7);
+ }
+ if (m_ibf) {
+ BIT_SET(res , 0);
+ }
+ break;
+
+ case 1:
+ // Read OB
+ res = m_ob;
+ m_obf = false;
+ need_resched |= update_halt();
+ break;
+ }
+
+ if (need_resched) {
+ LOG("resched %s\n" , space.device().tag());
+ space.device().execute().spin();
+ }
+ //LOG("RDU %u=%02x\n" , offset , res);
+ return res;
+}
+
+WRITE8_MEMBER(hp_1mb5_device::uc_w)
+{
+ //LOG("WRU %u=%02x SR=%02x\n" , offset , data , m_sr);
+ bool need_resched = false;
+
+ switch (offset) {
+ case 0:
+ // Write SR
+ if (!BIT(m_sr , 0) && BIT(data , 0)) {
+ need_resched |= set_service(true);
+ }
+ m_sr = data;
+ m_hlten = BIT(m_sr , 7);
+ if (update_halt() && !m_halt) {
+ need_resched = true;
+ }
+ break;
+
+ case 1:
+ // Write IB
+ m_ib = data;
+ m_ibf = true;
+ need_resched |= update_halt();
+ break;
+ }
+ if (need_resched) {
+ LOG("resched %s\n" , space.device().tag());
+ space.device().execute().spin();
+ }
+}
+
+READ_LINE_MEMBER(hp_1mb5_device::irl_r)
+{
+ return m_service;
+}
+
+READ_LINE_MEMBER(hp_1mb5_device::halt_r)
+{
+ return m_halt;
+}
+
+READ_LINE_MEMBER(hp_1mb5_device::reset_r)
+{
+ return m_reset;
+}
+
+READ_LINE_MEMBER(hp_1mb5_device::int_r)
+{
+ return m_cint;
+}
+
+void hp_1mb5_device::inten()
+{
+ // Enabling interrupts (i.e. writing to 0xff40) removes uC reset
+ set_reset(false);
+}
+
+void hp_1mb5_device::clear_service()
+{
+ set_service(false);
+}
+
+void hp_1mb5_device::device_start()
+{
+ m_irl_handler.resolve_safe();
+ m_halt_handler.resolve_safe();
+ m_reset_handler.resolve_safe();
+ m_int_handler.resolve_safe();
+
+ save_item(NAME(m_sr));
+ save_item(NAME(m_cr));
+ save_item(NAME(m_ib));
+ save_item(NAME(m_ob));
+ save_item(NAME(m_ibf));
+ save_item(NAME(m_obf));
+ save_item(NAME(m_hlten));
+ save_item(NAME(m_service));
+ save_item(NAME(m_cint));
+ save_item(NAME(m_reset));
+ save_item(NAME(m_halt));
+}
+
+void hp_1mb5_device::device_reset()
+{
+ m_sr = 0;
+ m_cr = 0;
+ m_ib = 0;
+ m_ob = 0;
+ m_ibf = false;
+ m_obf = false;
+ m_hlten = false;
+ m_service = false;
+ m_cint = true;
+ m_reset = true;
+ m_halt = false;
+
+ m_irl_handler(false);
+ m_halt_handler(false);
+ m_reset_handler(true);
+ m_int_handler(true);
+}
+
+bool hp_1mb5_device::set_service(bool new_service)
+{
+ if (new_service != m_service) {
+ m_service = new_service;
+ //LOG("irl=%d\n" , m_service);
+ m_irl_handler(m_service);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool hp_1mb5_device::update_halt()
+{
+ bool new_halt = m_hlten && m_obf && !m_ibf;
+ if (new_halt != m_halt) {
+ //LOG("HALT=%d\n" , new_halt);
+ m_halt = new_halt;
+ m_halt_handler(m_halt);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool hp_1mb5_device::set_reset(bool new_reset)
+{
+ if (new_reset != m_reset) {
+ m_reset = new_reset;
+ m_reset_handler(m_reset);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool hp_1mb5_device::set_int(bool new_int)
+{
+ if (new_int != m_cint) {
+ m_cint = new_int;
+ LOG("cint=%d\n" , m_cint);
+ m_int_handler(m_cint);
+ return true;
+ } else {
+ return false;
+ }
+}