summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author shattered <shattered@users.noreply.github.com>2025-10-03 17:37:42 +0300
committer GitHub <noreply@github.com>2025-10-03 10:37:42 -0400
commit957cb0df46957e7bb2d1f57efb05f7648651b684 (patch)
tree8b1de5ab101fd6be85d590fb10d393751669c330
parente9d363e8700999a41f7755682b41ac0a464bcc16 (diff)
bk: add simulation of K1801VM1 on-chip timer (#14238)
* bk: add simulation of K1801VM1 on-chip timer
-rw-r--r--src/mame/ussr/bk.cpp9
-rw-r--r--src/mame/ussr/bk.h3
-rw-r--r--src/mame/ussr/bk_m.cpp1
-rw-r--r--src/mame/ussr/vm1timer.cpp184
-rw-r--r--src/mame/ussr/vm1timer.h63
5 files changed, 258 insertions, 2 deletions
diff --git a/src/mame/ussr/bk.cpp b/src/mame/ussr/bk.cpp
index bb502e2254e..063533adb4c 100644
--- a/src/mame/ussr/bk.cpp
+++ b/src/mame/ussr/bk.cpp
@@ -44,7 +44,8 @@ void bk_state::bk0010_mem(address_map &map)
map(0177660, 0177663).r(m_kbd, FUNC(k1801vp014_device::read));
map(0177660, 0177661).w(m_kbd, FUNC(k1801vp014_device::write));
map(0177664, 0177665).rw(FUNC(bk_state::vid_scroll_r), FUNC(bk_state::vid_scroll_w));
- map(0177706, 0177715).noprw();
+ map(0177706, 0177713).rw(m_timer, FUNC(k1801vm1_timer_device::read), FUNC(k1801vm1_timer_device::write));
+ map(0177714, 0177715).noprw();
map(0177716, 0177717).rw(FUNC(bk_state::sel1_r), FUNC(bk_state::sel1_w));
}
@@ -93,7 +94,8 @@ void bk_state::bk0011_mem(address_map &map)
m_stop_disabled = BIT(data, 15);
}));
map(0177664, 0177665).rw(FUNC(bk_state::vid_scroll_r), FUNC(bk_state::vid_scroll_w));
- map(0177706, 0177715).noprw();
+ map(0177706, 0177713).rw(m_timer, FUNC(k1801vm1_timer_device::read), FUNC(k1801vm1_timer_device::write));
+ map(0177714, 0177715).noprw();
map(0177716, 0177717).rw(FUNC(bk_state::bk11_sel1_r), FUNC(bk_state::bk11_sel1_w));
}
@@ -136,6 +138,7 @@ void bk_state::bk0010(machine_config &config)
m_maincpu->set_daisy_config(daisy_chain);
m_maincpu->out_reset().set(FUNC(bk_state::reset_w));
+ K1801VM1_TIMER(config, m_timer, 3000000);
K1801VP014(config, m_kbd, 0);
m_kbd->virq_wr_callback().set_inputline(m_maincpu, t11_device::VEC_LINE);
@@ -196,6 +199,8 @@ void bk_state::bk0011(machine_config &config)
m_maincpu->set_daisy_config(daisy_chain);
m_maincpu->out_reset().set(FUNC(bk_state::reset_w));
+ K1801VM1_TIMER(config.replace(), m_timer, 4000000);
+
m_kbd->halt_wr_callback().set([this] (int state) {
if (!m_stop_disabled) m_maincpu->set_input_line(t11_device::HLT_LINE, state);
});
diff --git a/src/mame/ussr/bk.h b/src/mame/ussr/bk.h
index 59b35ee6e94..48fc4f2a5f3 100644
--- a/src/mame/ussr/bk.h
+++ b/src/mame/ussr/bk.h
@@ -19,6 +19,7 @@
#include "machine/pdp11.h"
#include "machine/timer.h"
#include "sound/dac.h"
+#include "vm1timer.h"
#include "emupal.h"
@@ -32,6 +33,7 @@ public:
, m_palette(*this, "palette")
, m_cassette(*this, "cassette")
, m_dac(*this, "dac")
+ , m_timer(*this, "timer")
, m_kbd(*this, "keyboard")
, m_qbus(*this, "qbus")
, m_ram(*this, "ram%u", 0U)
@@ -88,6 +90,7 @@ private:
required_device<palette_device> m_palette;
required_device<cassette_image_device> m_cassette;
required_device<dac_bit_interface> m_dac;
+ required_device<k1801vm1_timer_device> m_timer;
required_device<k1801vp014_device> m_kbd;
required_device<qbus_device> m_qbus;
optional_shared_ptr_array<uint16_t, 8> m_ram;
diff --git a/src/mame/ussr/bk_m.cpp b/src/mame/ussr/bk_m.cpp
index 2e070849d47..d2abe2b52c4 100644
--- a/src/mame/ussr/bk_m.cpp
+++ b/src/mame/ussr/bk_m.cpp
@@ -40,6 +40,7 @@ void bk_state::reset_w(int state)
if (state == ASSERT_LINE)
{
m_kbd->reset();
+ m_timer->init_w();
m_qbus->init_w();
}
}
diff --git a/src/mame/ussr/vm1timer.cpp b/src/mame/ussr/vm1timer.cpp
new file mode 100644
index 00000000000..a9e684cda90
--- /dev/null
+++ b/src/mame/ussr/vm1timer.cpp
@@ -0,0 +1,184 @@
+// license:BSD-3-Clause
+// copyright-holders:Sergey Svishchev
+/**********************************************************************
+
+ K1801VM1 on-chip timer
+
+ https://github.com/1801BM1/cpu11/blob/master/vm1/doc/1801vm1.pdf
+ https://zx-pk.ru/threads/15090.html
+
+ Not implemented:
+ - SP mode (external trigger)
+ - IRQ (only present on die revision G)
+
+**********************************************************************/
+
+#include "emu.h"
+#include "vm1timer.h"
+
+#define VERBOSE (LOG_GENERAL)
+#include "logmacro.h"
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(K1801VM1_TIMER, k1801vm1_timer_device, "1801vm1_timer", "1801VM1 timer")
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+
+//-------------------------------------------------
+// k1801vm1_timer_device - constructor
+//-------------------------------------------------
+
+k1801vm1_timer_device::k1801vm1_timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, K1801VM1_TIMER, tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void k1801vm1_timer_device::device_start()
+{
+ // register for state saving
+ save_item(NAME(m_csr));
+ save_item(NAME(m_limit));
+ save_item(NAME(m_counter));
+
+ m_timer = timer_alloc(FUNC(k1801vm1_timer_device::timer_tick), this);
+ m_reload = timer_alloc(FUNC(k1801vm1_timer_device::timer_reload), this);
+ m_timer->adjust(attotime::never, 0, attotime::never);
+ m_reload->adjust(attotime::never, 0, attotime::never);
+
+ m_limit = rand();
+ m_counter = rand();
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void k1801vm1_timer_device::device_reset()
+{
+ init_w();
+}
+
+void k1801vm1_timer_device::init_w()
+{
+// m_limit is not reset by INIT or DCLO
+ m_csr = 0;
+}
+
+
+//-------------------------------------------------
+// read - register read
+//-------------------------------------------------
+
+uint16_t k1801vm1_timer_device::read(offs_t offset)
+{
+ uint16_t data = 0;
+
+ switch (offset)
+ {
+ case 0:
+ data = m_limit;
+ break;
+
+ case 1:
+ data = m_counter;
+ break;
+
+ case 2:
+ data = m_csr | 0177400;
+ break;
+ }
+
+ return data;
+}
+
+//-------------------------------------------------
+// write - register write
+//-------------------------------------------------
+
+void k1801vm1_timer_device::write(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOG("%s W %06o <- %06o & %06o\n", machine().describe_context(), 0177706 + (offset << 1), data, mem_mask);
+
+ switch (offset)
+ {
+ case 0:
+ m_limit = data;
+ break;
+
+ case 2:
+ if (BIT(data, 4))
+ {
+ int divisor = 128;
+ if (BIT(data, 5)) divisor *= 16;
+ if (BIT(data, 6)) divisor *= 4;
+ m_timer->adjust(attotime::from_hz(clock() / divisor), 0, attotime::from_hz(clock() / divisor));
+ LOG("%11.6f timer set: %u. limit (%u. cur) %d div (%d hz), oneshot %d, err %d\n",
+ machine().time().as_double(), m_limit, m_counter, divisor, clock()/divisor, BIT(data, 3), BIT(m_csr, 15));
+ }
+ else
+ {
+ m_timer->adjust(attotime::never, 0, attotime::never);
+ LOG("%11.6f timer stopped\n", machine().time().as_double());
+ }
+
+ m_csr = ((m_csr & ~TMRCSR_WR) | (data & TMRCSR_WR));
+ m_counter = m_limit;
+
+ break;
+ }
+}
+
+TIMER_CALLBACK_MEMBER(k1801vm1_timer_device::timer_tick)
+{
+ // external trigger mode
+ if (m_csr & TMRCSR_SP) return;
+
+ if (--m_counter == 0)
+ {
+ LOG("%11.6f timer done err %d ovf %d irq %d\n", machine().time().as_double(), BIT(m_csr, 15), BIT(m_csr, 7), BIT(m_csr, 2));
+ if (m_csr & TMRCSR_MON)
+ {
+ if (m_csr & CSR_ERR)
+ m_csr |= TMRCSR_FL;
+ m_csr |= CSR_ERR;
+ }
+
+ if (!(m_csr & TMRCSR_CAP))
+ {
+ if (m_csr & TMRCSR_OS)
+ {
+ m_csr &= ~TMRCSR_RUN;
+ m_timer->adjust(attotime::never, 0, attotime::never);
+ LOG("timer stopped (OS)\n");
+ }
+ m_reload->adjust(attotime::from_hz(clock() / 4));
+ }
+ }
+}
+
+TIMER_CALLBACK_MEMBER(k1801vm1_timer_device::timer_reload)
+{
+ LOG("%11.6f timer reloaded\n", machine().time().as_double());
+ m_counter = m_limit;
+}
diff --git a/src/mame/ussr/vm1timer.h b/src/mame/ussr/vm1timer.h
new file mode 100644
index 00000000000..1b5619d2ba1
--- /dev/null
+++ b/src/mame/ussr/vm1timer.h
@@ -0,0 +1,63 @@
+// license:BSD-3-Clause
+// copyright-holders:Sergey Svishchev
+/**********************************************************************
+
+ K1801VM1 on-chip timer
+
+**********************************************************************/
+
+#ifndef MAME_USSR_VM1TIMER_H
+#define MAME_USSR_VM1TIMER_H
+
+#pragma once
+
+#include "machine/pdp11.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class k1801vm1_timer_device : public device_t
+{
+public:
+ // construction/destruction
+ k1801vm1_timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ uint16_t read(offs_t offset);
+ void write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+
+ void init_w();
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ static constexpr uint16_t TMRCSR_SP = 0001;
+ static constexpr uint16_t TMRCSR_CAP = 0002;
+ static constexpr uint16_t TMRCSR_MON = 0004;
+ static constexpr uint16_t TMRCSR_OS = 0010;
+ static constexpr uint16_t TMRCSR_RUN = 0020;
+ static constexpr uint16_t TMRCSR_D16 = 0040;
+ static constexpr uint16_t TMRCSR_D4 = 0100;
+ static constexpr uint16_t TMRCSR_FL = 0200;
+ static constexpr uint16_t TMRCSR_WR = 0377;
+
+ uint16_t m_csr;
+ uint16_t m_counter;
+ uint16_t m_limit;
+
+ emu_timer *m_timer;
+ emu_timer *m_reload;
+
+ TIMER_CALLBACK_MEMBER(timer_tick);
+ TIMER_CALLBACK_MEMBER(timer_reload);
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(K1801VM1_TIMER, k1801vm1_timer_device)
+
+#endif // MAME_USSR_VM1TIMER_H