diff options
| author | 2025-10-03 17:37:42 +0300 | |
|---|---|---|
| committer | 2025-10-03 10:37:42 -0400 | |
| commit | 957cb0df46957e7bb2d1f57efb05f7648651b684 (patch) | |
| tree | 8b1de5ab101fd6be85d590fb10d393751669c330 | |
| parent | e9d363e8700999a41f7755682b41ac0a464bcc16 (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.cpp | 9 | ||||
| -rw-r--r-- | src/mame/ussr/bk.h | 3 | ||||
| -rw-r--r-- | src/mame/ussr/bk_m.cpp | 1 | ||||
| -rw-r--r-- | src/mame/ussr/vm1timer.cpp | 184 | ||||
| -rw-r--r-- | src/mame/ussr/vm1timer.h | 63 |
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 |
