From 273ec503fbf9e3aab6f2e18b0ff8f2a44bf76294 Mon Sep 17 00:00:00 2001 From: AJR Date: Tue, 5 Nov 2019 19:10:48 -0500 Subject: st2xxx: Refactoring (nw) - Centralize emulation of several common features - Add logging for interrupts and base timer - Fix error in debug state registration of IREQ and IENA - Correct base timer interrupt vector for ST2205U --- src/devices/cpu/m6502/st2204.cpp | 200 ++++-------------------- src/devices/cpu/m6502/st2204.h | 45 +----- src/devices/cpu/m6502/st2205u.cpp | 223 ++++++--------------------- src/devices/cpu/m6502/st2205u.h | 35 +---- src/devices/cpu/m6502/st2xxx.cpp | 313 +++++++++++++++++++++++++++++++++++--- src/devices/cpu/m6502/st2xxx.h | 59 ++++++- 6 files changed, 449 insertions(+), 426 deletions(-) diff --git a/src/devices/cpu/m6502/st2204.cpp b/src/devices/cpu/m6502/st2204.cpp index 3a6c794ba8b..7bea561baf4 100644 --- a/src/devices/cpu/m6502/st2204.cpp +++ b/src/devices/cpu/m6502/st2204.cpp @@ -37,24 +37,13 @@ st2204_device::st2204_device(const machine_config &mconfig, const char *tag, dev : st2xxx_device(mconfig, ST2204, tag, owner, clock, address_map_constructor(FUNC(st2204_device::int_map), this), 26, // logical; only 23 address lines are brought out - 0x0f7f) - , m_bten(0) - , m_btsr(0) - , m_base_timer{0} + false) , m_dms(0) , m_dmd(0) , m_dcnth(0) { } -template -TIMER_CALLBACK_MEMBER(st2204_device::bt_interrupt) -{ - m_btsr |= 1 << N; - m_ireq |= 0x020; - update_irq_state(); -} - void st2204_device::device_start() { std::unique_ptr intf = std::make_unique(); @@ -67,43 +56,21 @@ void st2204_device::device_start() intf->dmr = 0; intf->irq_service = false; - m_base_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2204_device::bt_interrupt<0>), this)); - m_base_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2204_device::bt_interrupt<1>), this)); - m_base_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2204_device::bt_interrupt<2>), this)); - m_base_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2204_device::bt_interrupt<3>), this)); - m_base_timer[4] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2204_device::bt_interrupt<4>), this)); - - save_item(NAME(m_pdata)); - save_item(NAME(m_pctrl)); - save_item(NAME(m_psel)); - save_item(NAME(m_pfun)); - save_item(NAME(m_bten)); - save_item(NAME(m_btsr)); + init_base_timer(0x0020); + save_item(NAME(m_dms)); save_item(NAME(m_dmd)); save_item(NAME(m_dcnth)); - save_item(NAME(m_sys)); - save_item(NAME(m_pmcr)); - save_item(NAME(m_ireq)); - save_item(NAME(m_iena)); - save_item(NAME(m_lssa)); - save_item(NAME(m_lvpw)); - save_item(NAME(m_lxmax)); - save_item(NAME(m_lymax)); - save_item(NAME(intf->irr_enable)); - save_item(NAME(intf->irr)); - save_item(NAME(intf->prr)); - save_item(NAME(intf->drr)); - save_item(NAME(intf->irq_service)); mintf = std::move(intf); + save_common_registers(); init(); state_add(ST_IRR, "IRR", downcast(*mintf).irr).mask(0xff); state_add(ST_PRR, "PRR", downcast(*mintf).prr).mask(0xfff); state_add(ST_DRR, "DRR", downcast(*mintf).drr).mask(0x7ff); - state_add(ST_IREQ, "IREQ", [this]() { return m_ireq; }, [this](u16 data) { m_ireq = data; update_irq_state(); }).mask(m_ireq_mask); - state_add(ST_IENA, "IENA", [this]() { return m_iena; }, [this](u16 data) { m_iena = data; update_irq_state(); }).mask(m_ireq_mask); + state_add(ST_IREQ, "IREQ", [this]() { return m_ireq; }, [this](u16 data) { m_ireq = data; update_irq_state(); }).mask(st2xxx_ireq_mask()); + state_add(ST_IENA, "IENA", [this]() { return m_iena; }, [this](u16 data) { m_iena = data; update_irq_state(); }).mask(st2xxx_ireq_mask()); for (int i = 0; i < 5; i++) { state_add(ST_PDA + i, string_format("PD%c", 'A' + i).c_str(), m_pdata[i]); @@ -131,16 +98,25 @@ void st2204_device::device_start() void st2204_device::device_reset() { st2xxx_device::device_reset(); +} - mi_st2204 &m = downcast(*mintf); - m.irr_enable = false; - m.irr = 0; - m.prr = 0; - m.drr = 0; - m.dmr = 0; - - bten_w(0); - m_btsr = 0; +const char *st2204_device::st2xxx_irq_name(int i) const +{ + switch (i) + { + case 0: return "PC0 edge"; + case 1: return "DAC reload"; + case 2: return "Timer 0"; + case 3: return "Timer 1"; + case 4: return "PA transition"; + case 5: return "Base timer"; + case 6: return "LCD frame"; + case 8: return "SPI TX empty"; + case 9: return "SPI RX ready"; + case 10: return "UART TX"; + case 11: return "UART RX"; + default: return "Reserved"; + } } u8 st2204_device::mi_st2204::pread(u16 adr) @@ -219,103 +195,13 @@ void st2204_device::pmcr_w(u8 data) m_pmcr = data; } -u8 st2204_device::bten_r() -{ - return m_bten; -} - -void st2204_device::bten_w(u8 data) -{ - for (int n = 0; n < 5; n++) - { - if (BIT(data, n) && !BIT(m_bten, n)) - { - // 2 Hz, 8 Hz, 64 Hz, 256 Hz, 2048 Hz - attotime period = attotime::from_hz(2 << ((n & 1) * 2 + (n >> 1) * 5)); - m_base_timer[n]->adjust(period, 0, period); - } - else if (!BIT(data, n) && BIT(m_bten, n)) - m_base_timer[n]->adjust(attotime::never); - } - - m_bten = data & 0x1f; -} - -u8 st2204_device::btsr_r() -{ - return m_btsr; -} - -void st2204_device::btsr_w(u8 data) -{ - // Only bit 7 has any effect - if (BIT(data, 7)) - m_btsr = 0; -} - -u8 st2204_device::sys_r() -{ - return m_sys | 0x01; -} - -void st2204_device::sys_w(u8 data) -{ - m_sys = data; - downcast(*mintf).irr_enable = BIT(data, 1); -} - -u8 st2204_device::irr_r() -{ - return downcast(*mintf).irr; -} - -void st2204_device::irr_w(u8 data) -{ - downcast(*mintf).irr = data; -} - -u8 st2204_device::prrl_r() -{ - return downcast(*mintf).prr & 0xff; -} - -void st2204_device::prrl_w(u8 data) -{ - u16 &prr = downcast(*mintf).prr; - prr = data | (prr & 0x0f00); -} - -u8 st2204_device::prrh_r() -{ - return downcast(*mintf).prr >> 8; -} - -void st2204_device::prrh_w(u8 data) -{ - u16 &prr = downcast(*mintf).prr; - prr = u16(data & 0x0f) << 8 | (prr & 0x00ff); -} - -u8 st2204_device::drrl_r() -{ - return downcast(*mintf).drr & 0xff; -} - -void st2204_device::drrl_w(u8 data) -{ - u16 &drr = downcast(*mintf).drr; - drr = data | (drr & 0x0700); -} - -u8 st2204_device::drrh_r() -{ - return downcast(*mintf).drr >> 8; -} - -void st2204_device::drrh_w(u8 data) +unsigned st2204_device::st2xxx_bt_divider(int n) const { - u16 &drr = downcast(*mintf).drr; - drr = u16(data & 0x07) << 8 | (drr & 0x00ff); + // 2 Hz, 8 Hz, 64 Hz, 256 Hz, 2048 Hz + if (n < 5) + return 16384 >> ((n & 1) * 2 + (n >> 1) * 5); + else + return 0; } u8 st2204_device::dmsl_r() @@ -388,28 +274,6 @@ void st2204_device::dcnth_w(u8 data) m_dcnth = data & 0x1f; } -u8 st2204_device::dmrl_r() -{ - return downcast(*mintf).dmr & 0xff; -} - -void st2204_device::dmrl_w(u8 data) -{ - u16 &dmr = downcast(*mintf).dmr; - dmr = data | (dmr & 0x0700); -} - -u8 st2204_device::dmrh_r() -{ - return downcast(*mintf).dmr >> 8; -} - -void st2204_device::dmrh_w(u8 data) -{ - u16 &dmr = downcast(*mintf).dmr; - dmr = (data & 0x07) << 8 | (dmr & 0x00ff); -} - u8 st2204_device::pmem_r(offs_t offset) { return downcast(*mintf).pread(offset); @@ -439,7 +303,7 @@ void st2204_device::int_map(address_map &map) map(0x000e, 0x000e).rw(FUNC(st2204_device::pfd_r), FUNC(st2204_device::pfd_w)); map(0x000f, 0x000f).rw(FUNC(st2204_device::pmcr_r), FUNC(st2204_device::pmcr_w)); map(0x0020, 0x0020).rw(FUNC(st2204_device::bten_r), FUNC(st2204_device::bten_w)); - map(0x0021, 0x0021).rw(FUNC(st2204_device::btsr_r), FUNC(st2204_device::btsr_w)); + map(0x0021, 0x0021).rw(FUNC(st2204_device::btsr_r), FUNC(st2204_device::btclr_all_w)); // Source/destination registers are not readable on ST2202, but may be readable here (count register isn't) map(0x0028, 0x0028).rw(FUNC(st2204_device::dmsl_r), FUNC(st2204_device::dmsl_w)); map(0x0029, 0x0029).rw(FUNC(st2204_device::dmsh_r), FUNC(st2204_device::dmsh_w)); @@ -448,7 +312,7 @@ void st2204_device::int_map(address_map &map) map(0x002c, 0x002c).w(FUNC(st2204_device::dcntl_w)); map(0x002d, 0x002d).w(FUNC(st2204_device::dcnth_w)); map(0x0030, 0x0030).rw(FUNC(st2204_device::sys_r), FUNC(st2204_device::sys_w)); - map(0x0031, 0x0031).rw(FUNC(st2204_device::irr_r), FUNC(st2204_device::irr_w)); + map(0x0031, 0x0031).rw(FUNC(st2204_device::irrl_r), FUNC(st2204_device::irrl_w)); map(0x0032, 0x0032).rw(FUNC(st2204_device::prrl_r), FUNC(st2204_device::prrl_w)); map(0x0033, 0x0033).rw(FUNC(st2204_device::prrh_r), FUNC(st2204_device::prrh_w)); map(0x0034, 0x0034).rw(FUNC(st2204_device::drrl_r), FUNC(st2204_device::drrl_w)); diff --git a/src/devices/cpu/m6502/st2204.h b/src/devices/cpu/m6502/st2204.h index 63ef404ea48..fbc1f69563d 100644 --- a/src/devices/cpu/m6502/st2204.h +++ b/src/devices/cpu/m6502/st2204.h @@ -17,11 +17,8 @@ class st2204_device : public st2xxx_device { public: enum { - ST_BTEN = ST_LYMAX + 1, - ST_BTSR, - ST_DMS, - ST_DMD, - ST_DMR + ST_DMS = ST_LYMAX + 1, + ST_DMD }; st2204_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); @@ -30,6 +27,12 @@ protected: virtual void device_start() override; virtual void device_reset() override; + virtual u16 st2xxx_ireq_mask() const override { return 0x0f7f; } + virtual const char *st2xxx_irq_name(int i) const override; + virtual unsigned st2xxx_bt_divider(int n) const override; + virtual u8 st2xxx_sys_mask() const override { return 0xff; } + virtual bool st2xxx_has_dma() const override { return true; } + private: class mi_st2204 : public mi_st2xxx { public: @@ -46,34 +49,10 @@ private: u8 dread(u16 adr); u8 dreadc(u16 adr); void dwrite(u16 adr, u8 val); - - bool irr_enable; - u8 irr; - u16 prr; - u16 drr; - u16 dmr; }; - template TIMER_CALLBACK_MEMBER(bt_interrupt); - - u8 sys_r(); - void sys_w(u8 data); - u8 irr_r(); - void irr_w(u8 data); - u8 prrl_r(); - void prrl_w(u8 data); - u8 prrh_r(); - void prrh_w(u8 data); - u8 drrl_r(); - void drrl_w(u8 data); - u8 drrh_r(); - void drrh_w(u8 data); u8 pmcr_r(); void pmcr_w(u8 data); - u8 bten_r(); - void bten_w(u8 data); - u8 btsr_r(); - void btsr_w(u8 data); u8 dmsl_r(); void dmsl_w(u8 data); u8 dmsh_r(); @@ -84,10 +63,6 @@ private: void dmdh_w(u8 data); void dcntl_w(u8 data); void dcnth_w(u8 data); - u8 dmrl_r(); - void dmrl_w(u8 data); - u8 dmrh_r(); - void dmrh_w(u8 data); u8 pmem_r(offs_t offset); void pmem_w(offs_t offset, u8 data); @@ -96,10 +71,6 @@ private: void int_map(address_map &map); - u8 m_bten; - u8 m_btsr; - emu_timer *m_base_timer[5]; - u16 m_dms; u16 m_dmd; u8 m_dcnth; diff --git a/src/devices/cpu/m6502/st2205u.cpp b/src/devices/cpu/m6502/st2205u.cpp index e43b79dc449..180300cdb64 100644 --- a/src/devices/cpu/m6502/st2205u.cpp +++ b/src/devices/cpu/m6502/st2205u.cpp @@ -39,23 +39,12 @@ st2205u_device::st2205u_device(const machine_config &mconfig, const char *tag, d : st2xxx_device(mconfig, ST2205U, tag, owner, clock, address_map_constructor(FUNC(st2205u_device::int_map), this), 26, // logical; only 23 address lines are brought out - 0xdfff) - , m_bten(0) - , m_btreq(0) + true) , m_btc(0) - , m_base_timer{0} , m_lvctr(0) { } -template -TIMER_CALLBACK_MEMBER(st2205u_device::bt_interrupt) -{ - m_btreq |= 1 << N; - m_ireq |= 0x0020; - update_irq_state(); -} - void st2205u_device::device_start() { std::unique_ptr intf = std::make_unique(); @@ -67,51 +56,24 @@ void st2205u_device::device_start() intf->drr = 0; intf->brr = 0; intf->irq_service = false; - - m_base_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2205u_device::bt_interrupt<0>), this)); - m_base_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2205u_device::bt_interrupt<1>), this)); - m_base_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2205u_device::bt_interrupt<2>), this)); - m_base_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2205u_device::bt_interrupt<3>), this)); - m_base_timer[4] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2205u_device::bt_interrupt<4>), this)); - m_base_timer[5] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2205u_device::bt_interrupt<5>), this)); - m_base_timer[6] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2205u_device::bt_interrupt<6>), this)); - m_base_timer[7] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2205u_device::bt_interrupt<7>), this)); - intf->ram = make_unique_clear(0x8000); - save_item(NAME(m_pdata)); - save_item(NAME(m_pctrl)); - save_item(NAME(m_psel)); - save_item(NAME(m_pfun)); - save_item(NAME(m_bten)); - save_item(NAME(m_btreq)); + init_base_timer(0x0040); + save_item(NAME(m_btc)); - save_item(NAME(m_sys)); - save_item(NAME(m_pmcr)); - save_item(NAME(m_ireq)); - save_item(NAME(m_iena)); - save_item(NAME(m_lssa)); - save_item(NAME(m_lvpw)); - save_item(NAME(m_lxmax)); - save_item(NAME(m_lymax)); - save_item(NAME(m_lvctr)); - save_item(NAME(intf->irr_enable)); - save_item(NAME(intf->irr)); - save_item(NAME(intf->prr)); - save_item(NAME(intf->drr)); save_item(NAME(intf->brr)); - save_item(NAME(intf->irq_service)); save_pointer(NAME(intf->ram), 0x8000); mintf = std::move(intf); + save_common_registers(); init(); state_add(ST_IRR, "IRR", downcast(*mintf).irr).mask(0x87ff); state_add(ST_PRR, "PRR", downcast(*mintf).prr).mask(0x87ff); state_add(ST_DRR, "DRR", downcast(*mintf).drr).mask(0x8fff); state_add(ST_BRR, "BRR", downcast(*mintf).brr).mask(0x9fff); - state_add(ST_IREQ, "IREQ", [this]() { return m_ireq; }, [this](u16 data) { m_ireq = data; update_irq_state(); }).mask(m_ireq_mask); - state_add(ST_IENA, "IENA", [this]() { return m_iena; }, [this](u16 data) { m_iena = data; update_irq_state(); }).mask(m_ireq_mask); + state_add(ST_IREQ, "IREQ", [this]() { return m_ireq; }, [this](u16 data) { m_ireq = data; update_irq_state(); }).mask(st2xxx_ireq_mask()); + state_add(ST_IENA, "IENA", [this]() { return m_iena; }, [this](u16 data) { m_iena = data; update_irq_state(); }).mask(st2xxx_ireq_mask()); for (int i = 0; i < 6; i++) { state_add(ST_PDA + i, string_format("PD%c", 'A' + i).c_str(), m_pdata[i]); @@ -126,7 +88,7 @@ void st2205u_device::device_start() state_add(ST_PMCR, "PMCR", m_pmcr); state_add(ST_SYS, "SYS", [this]() { return m_sys; }, [this](u8 data) { sys_w(data); }).mask(0xfe); state_add(ST_BTEN, "BTEN", [this]() { return m_bten; }, [this](u8 data) { bten_w(data); }); - state_add(ST_BTREQ, "BTREQ", m_btreq); + state_add(ST_BTSR, "BTREQ", m_btsr); state_add(ST_BTC, "BTC", m_btc); state_add(ST_LSSA, "LSSA", m_lssa); state_add(ST_LVPW, "LVPW", m_lvpw); @@ -139,22 +101,39 @@ void st2205u_device::device_reset() { st2xxx_device::device_reset(); - mi_st2205u &m = downcast(*mintf); - m.irr_enable = false; - m.irr = 0; - m.prr = 0; - m.drr = 0; + downcast(*mintf).brr = 0; - bten_w(0); - m_btreq = 0; m_btc = 0; m_lvctr = 0; } +const char *st2205u_device::st2xxx_irq_name(int i) const +{ + switch (i) + { + case 0: return "PE0/1/2 edge"; + case 1: return "Timer 0"; + case 2: return "Timer 1"; + case 3: return "Timer 2"; + case 4: return "Timer 3"; + case 5: return "PA transition"; + case 6: return "Base timer"; + case 7: return "LCD buffer"; + case 8: return "SPI TX empty"; + case 9: return "SPI RX ready"; + case 10: return "UART TX"; + case 11: return "UART RX"; + case 12: return "USB"; + case 14: return "PCM"; + case 15: return "RTC"; + default: return "Reserved"; + } +} + u8 st2205u_device::mi_st2205u::pread(u16 adr) { - u16 bank = irq_service ? irr : prr; + u16 bank = irq_service && irr_enable ? irr : prr; if (BIT(bank, 15)) return ram[0x4000 | (adr & 0x3fff)]; else @@ -163,7 +142,7 @@ u8 st2205u_device::mi_st2205u::pread(u16 adr) u8 st2205u_device::mi_st2205u::preadc(u16 adr) { - u16 bank = irq_service ? irr : prr; + u16 bank = irq_service && irr_enable ? irr : prr; if (BIT(bank, 15)) return ram[0x4000 | (adr & 0x3fff)]; else @@ -172,7 +151,7 @@ u8 st2205u_device::mi_st2205u::preadc(u16 adr) void st2205u_device::mi_st2205u::pwrite(u16 adr, u8 val) { - u16 bank = irq_service ? irr : prr; + u16 bank = irq_service && irr_enable ? irr : prr; if (BIT(bank, 15)) ram[0x4000 | (adr & 0x3fff)] = val; else @@ -252,72 +231,6 @@ void st2205u_device::mi_st2205u::write(u16 adr, u8 val) program->write_byte(adr, val); } -u8 st2205u_device::irrl_r() -{ - return downcast(*mintf).irr & 0xff; -} - -void st2205u_device::irrl_w(u8 data) -{ - u16 &irr = downcast(*mintf).irr; - irr = data | (irr & 0x8f00); -} - -u8 st2205u_device::irrh_r() -{ - return downcast(*mintf).irr >> 8; -} - -void st2205u_device::irrh_w(u8 data) -{ - u16 &irr = downcast(*mintf).irr; - irr = (data & 0x8f) << 8 | (irr & 0x00ff); -} - -u8 st2205u_device::prrl_r() -{ - return downcast(*mintf).prr & 0xff; -} - -void st2205u_device::prrl_w(u8 data) -{ - u16 &prr = downcast(*mintf).prr; - prr = data | (prr & 0x8f00); -} - -u8 st2205u_device::prrh_r() -{ - return downcast(*mintf).prr >> 8; -} - -void st2205u_device::prrh_w(u8 data) -{ - u16 &prr = downcast(*mintf).prr; - prr = (data & 0x8f) << 8 | (prr & 0x00ff); -} - -u8 st2205u_device::drrl_r() -{ - return downcast(*mintf).drr & 0xff; -} - -void st2205u_device::drrl_w(u8 data) -{ - u16 &drr = downcast(*mintf).drr; - drr = data | (drr & 0x8700); -} - -u8 st2205u_device::drrh_r() -{ - return downcast(*mintf).drr >> 8; -} - -void st2205u_device::drrh_w(u8 data) -{ - u16 &drr = downcast(*mintf).drr; - drr = (data & 0x87) << 8 | (drr & 0x00ff); -} - u8 st2205u_device::brrl_r() { return downcast(*mintf).brr & 0xff; @@ -350,61 +263,23 @@ void st2205u_device::pmcr_w(u8 data) m_pmcr = data; } -u8 st2205u_device::sys_r() +unsigned st2205u_device::st2xxx_bt_divider(int n) const { - return m_sys; -} + // 2 Hz + if (n == 0) + return 16384; -void st2205u_device::sys_w(u8 data) -{ - m_sys = data & 0xfe; - downcast(*mintf).irr_enable = BIT(data, 1); -} + // 32 Hz, 64 Hz, 128 Hz, 256 Hz, 512 Hz + if (n <= 5) + return 2048 >> n; -u8 st2205u_device::bten_r() -{ - return m_bten; -} - -void st2205u_device::bten_w(u8 data) -{ - if (BIT(data, 0) && !BIT(m_bten, 0)) - m_base_timer[0]->adjust(attotime::from_hz(2), 0, attotime::from_hz(2)); - else if (!BIT(data, 0) && BIT(m_bten, 0)) - m_base_timer[0]->adjust(attotime::never); - - for (int n = 1; n <= 5; n++) - { - if (BIT(data, n) && !BIT(m_bten, n)) - m_base_timer[n]->adjust(attotime::from_hz(16 << n), 0, attotime::from_hz(16 << n)); - else if (!BIT(data, n) && BIT(m_bten, n)) - m_base_timer[n]->adjust(attotime::never); - } - - if (BIT(data, 6) && !BIT(m_bten, 6)) - m_base_timer[6]->adjust(attotime::from_hz(2048), 0, attotime::from_hz(2048)); - else if (!BIT(data, 6) && BIT(m_bten, 6)) - m_base_timer[6]->adjust(attotime::never); - - if (BIT(data, 7) && !BIT(m_bten, 7)) - { - attotime period = attotime::from_hz(8192) * (m_btc ? m_btc : 256); - m_base_timer[7]->adjust(period, 0, period); - } - else if (!BIT(data, 7) && BIT(m_bten, 7)) - m_base_timer[7]->adjust(attotime::never); - - m_bten = data; -} + // 2048 Hz + if (n == 6) + return 16; -u8 st2205u_device::btreq_r() -{ - return m_btreq; -} - -void st2205u_device::btclr_w(u8 data) -{ - m_btreq &= ~data; + // 8192 Hz / BTC + assert(n == 7); + return 4 * (m_btc != 0 ? m_btc : 256); } u8 st2205u_device::btc_r() @@ -476,7 +351,7 @@ void st2205u_device::int_map(address_map &map) map(0x000e, 0x000e).rw(FUNC(st2205u_device::pfc_r), FUNC(st2205u_device::pfc_w)); map(0x000f, 0x000f).rw(FUNC(st2205u_device::pfd_r), FUNC(st2205u_device::pfd_w)); map(0x002a, 0x002a).rw(FUNC(st2205u_device::bten_r), FUNC(st2205u_device::bten_w)); - map(0x002b, 0x002b).rw(FUNC(st2205u_device::btreq_r), FUNC(st2205u_device::btclr_w)); + map(0x002b, 0x002b).rw(FUNC(st2205u_device::btsr_r), FUNC(st2205u_device::btclr_w)); map(0x002c, 0x002c).rw(FUNC(st2205u_device::btc_r), FUNC(st2205u_device::btc_w)); map(0x0030, 0x0030).rw(FUNC(st2205u_device::irrl_r), FUNC(st2205u_device::irrl_w)); map(0x0031, 0x0031).rw(FUNC(st2205u_device::irrh_r), FUNC(st2205u_device::irrh_w)); @@ -500,6 +375,8 @@ void st2205u_device::int_map(address_map &map) map(0x004e, 0x004e).rw(FUNC(st2205u_device::pl_r), FUNC(st2205u_device::pl_w)); map(0x004f, 0x004f).rw(FUNC(st2205u_device::pcl_r), FUNC(st2205u_device::pcl_w)); map(0x0057, 0x0057).rw(FUNC(st2205u_device::lvctr_r), FUNC(st2205u_device::lvctr_w)); + map(0x005a, 0x005a).rw(FUNC(st2205u_device::dmrl_r), FUNC(st2205u_device::dmrl_w)); + map(0x005b, 0x005b).rw(FUNC(st2205u_device::dmrh_r), FUNC(st2205u_device::dmrh_w)); map(0x0080, 0x1fff).rw(FUNC(st2205u_device::ram_r), FUNC(st2205u_device::ram_w)); // assumed to be shared with banked RAM map(0x2000, 0x3fff).rw(FUNC(st2205u_device::bmem_r), FUNC(st2205u_device::bmem_w)); map(0x4000, 0x7fff).rw(FUNC(st2205u_device::pmem_r), FUNC(st2205u_device::pmem_w)); diff --git a/src/devices/cpu/m6502/st2205u.h b/src/devices/cpu/m6502/st2205u.h index 2a04bc67be7..5eafabb9c74 100644 --- a/src/devices/cpu/m6502/st2205u.h +++ b/src/devices/cpu/m6502/st2205u.h @@ -17,9 +17,7 @@ class st2205u_device : public st2xxx_device { public: enum { - ST_BTEN = ST_LYMAX + 1, - ST_BTREQ, - ST_BTC, + ST_BTC = ST_LYMAX + 1, ST_BRR, ST_LVCTR }; @@ -30,6 +28,12 @@ protected: virtual void device_start() override; virtual void device_reset() override; + virtual u16 st2xxx_ireq_mask() const override { return 0xdfff; } + virtual const char *st2xxx_irq_name(int i) const override; + virtual unsigned st2xxx_bt_divider(int n) const override; + virtual u8 st2xxx_sys_mask() const override { return 0xfe; } + virtual bool st2xxx_has_dma() const override { return true; } + private: class mi_st2205u : public mi_st2xxx { public: @@ -49,10 +53,6 @@ private: u8 breadc(u16 adr); void bwrite(u16 adr, u8 val); - bool irr_enable; - u16 irr; - u16 prr; - u16 drr; u16 brr; std::unique_ptr ram; @@ -60,30 +60,12 @@ private: template TIMER_CALLBACK_MEMBER(bt_interrupt); - u8 irrl_r(); - void irrl_w(u8 data); - u8 irrh_r(); - void irrh_w(u8 data); - u8 prrl_r(); - void prrl_w(u8 data); - u8 prrh_r(); - void prrh_w(u8 data); - u8 drrl_r(); - void drrl_w(u8 data); - u8 drrh_r(); - void drrh_w(u8 data); u8 brrl_r(); void brrl_w(u8 data); u8 brrh_r(); void brrh_w(u8 data); - u8 sys_r(); - void sys_w(u8 data); u8 pmcr_r(); void pmcr_w(u8 data); - u8 bten_r(); - void bten_w(u8 data); - u8 btreq_r(); - void btclr_w(u8 data); u8 btc_r(); void btc_w(u8 data); u8 lvctr_r(); @@ -100,10 +82,7 @@ private: void int_map(address_map &map); - u8 m_bten; - u8 m_btreq; u8 m_btc; - emu_timer *m_base_timer[8]; u8 m_lvctr; }; diff --git a/src/devices/cpu/m6502/st2xxx.cpp b/src/devices/cpu/m6502/st2xxx.cpp index ce5a91ba619..a7a5a84be8c 100644 --- a/src/devices/cpu/m6502/st2xxx.cpp +++ b/src/devices/cpu/m6502/st2xxx.cpp @@ -28,20 +28,34 @@ #include "emu.h" #include "st2xxx.h" -st2xxx_device::st2xxx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor internal_map, int data_bits, u16 ireq_mask) +#define LOG_IRQ (1 << 1U) +#define LOG_BT (1 << 2U) +//#define VERBOSE (LOG_IRQ | LOG_BT) +#include "logmacro.h" + +st2xxx_device::st2xxx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor internal_map, int data_bits, bool has_banked_ram) : r65c02_device(mconfig, type, tag, owner, clock) , m_data_config("data", ENDIANNESS_LITTLE, 8, data_bits, 0) , m_in_port_cb{{*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}} , m_out_port_cb{{*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}} + , m_prr_mask(data_bits <= 14 ? 0 : ((u16(1) << (data_bits - 14)) - 1) | (has_banked_ram ? 0x8000 : 0)) + , m_drr_mask(data_bits <= 15 ? 0 : ((u16(1) << (data_bits - 15)) - 1) | (has_banked_ram ? 0x8000 : 0)) , m_pdata{0} , m_pctrl{0} , m_psel{0} , m_pfun{0} , m_pmcr(0) + , m_bten(0) + , m_btsr(0) + , m_bt_mask(0) + , m_bt_ireq(0) + , m_sys(0) , m_ireq(0) , m_iena(0) - , m_ireq_mask(ireq_mask) - , m_sys(0) + , m_lssa(0) + , m_lvpw(0) + , m_lxmax(0) + , m_lymax(0) { program_config.m_internal_map = std::move(internal_map); } @@ -62,6 +76,81 @@ void st2xxx_device::device_resolve_objects() cb.resolve_safe(); } +TIMER_CALLBACK_MEMBER(st2xxx_device::bt_interrupt) +{ + // BTSR must be cleared each time the interrupt is serviced + bool interrupt = (m_btsr == 0); + + m_btsr |= 1 << param; + + unsigned div = st2xxx_bt_divider(param); + assert(div != 0); + m_base_timer[param]->adjust(attotime::from_ticks(32768, div), param); + + if (interrupt) + { + LOGMASKED(LOG_BT, "Interrupt caused by %.1f Hz base timer\n", 32768.0 / div); + m_ireq |= m_bt_ireq; + update_irq_state(); + } +} + +void st2xxx_device::init_base_timer(u16 ireq) +{ + m_bt_ireq = ireq; + + for (int n = 0; n < 8; n++) + { + if (st2xxx_bt_divider(n) != 0) + { + m_bt_mask |= 1 << n; + m_base_timer[n] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2xxx_device::bt_interrupt), this)); + } + } + + assert(m_bt_mask != 0); + assert(m_bt_ireq != 0); +} + +void st2xxx_device::save_common_registers() +{ + mi_st2xxx *intf = downcast(mintf.get()); + + save_item(NAME(m_pdata)); + save_item(NAME(m_pctrl)); + save_item(NAME(m_psel)); + save_item(NAME(m_pfun)); + save_item(NAME(m_pmcr)); + if (m_prr_mask != 0) + { + if (BIT(st2xxx_sys_mask(), 1)) + { + save_item(NAME(intf->irq_service)); + save_item(NAME(intf->irr_enable)); + save_item(NAME(intf->irr)); + } + save_item(NAME(intf->prr)); + } + if (m_drr_mask != 0) + { + save_item(NAME(intf->drr)); + if (st2xxx_has_dma()) + save_item(NAME(intf->dmr)); + } + if (m_bt_mask != 0) + { + save_item(NAME(m_bten)); + save_item(NAME(m_btsr)); + } + save_item(NAME(m_sys)); + save_item(NAME(m_ireq)); + save_item(NAME(m_iena)); + save_item(NAME(m_lssa)); + save_item(NAME(m_lvpw)); + save_item(NAME(m_lxmax)); + save_item(NAME(m_lymax)); +} + void st2xxx_device::device_reset() { m6502_device::device_reset(); @@ -75,11 +164,23 @@ void st2xxx_device::device_reset() cb(0xff); m_pmcr = 0x80; + // reset bank registers + mi_st2xxx &m = downcast(*mintf); + m.irr_enable = false; + m.irr = 0; + m.prr = 0; + m.drr = 0; + m.dmr = 0; + // reset interrupt registers m_ireq = 0; m_iena = 0; update_irq_state(); + // reset base timer + bten_w(0); + m_btsr = 0; + // reset miscellaneous registers m_sys = 0; @@ -93,19 +194,15 @@ void st2xxx_device::device_reset() u8 st2xxx_device::acknowledge_irq() { // IREQH interrupts have priority over IREQL interrupts - for (int level = 8; level < 16; level++) - { - if (BIT(m_ireq & m_iena, level)) - { - m_ireq &= ~(1 << level); - update_irq_state(); - return level; - } - } - for (int level = 0; level < 8; level++) + for (int pri = 0; pri < 16; pri++) { + int level = pri ^ 8; if (BIT(m_ireq & m_iena, level)) { + LOGMASKED(LOG_IRQ, "%s interrupt acknowledged (PC = $%04X, vector = $%04X)\n", + st2xxx_irq_name(level), + PPC, + 0x7ff8 - (level << 1)); m_ireq &= ~(1 << level); update_irq_state(); return level; @@ -207,6 +304,154 @@ void st2xxx_device::pcl_w(u8 data) pctrl_w(6, data); } +u8 st2xxx_device::bten_r() +{ + return m_bten; +} + +void st2xxx_device::bten_w(u8 data) +{ + data &= m_bt_mask; + + for (int n = 0; n < 8; n++) + { + if (BIT(data, n) && !BIT(m_bten, n)) + { + unsigned div = st2xxx_bt_divider(n); + assert(div != 0); + assert(m_base_timer[n] != nullptr); + m_base_timer[n]->adjust(attotime::from_ticks(32768, div), n); + LOGMASKED(LOG_BT, "Base timer %d enabled at %.1f Hz (PC = $%04X)\n", n, 32768.0 / div, PPC); + } + else if (!BIT(data, n) && BIT(m_bten, n)) + { + m_base_timer[n]->adjust(attotime::never); + LOGMASKED(LOG_BT, "Base timer %d disabled (PC = $%04X)\n", n, PPC); + } + } + + m_bten = data; +} + +u8 st2xxx_device::btsr_r() +{ + return m_btsr; +} + +void st2xxx_device::btclr_w(u8 data) +{ + // Write 1 to clear each individual bit + m_btsr &= ~data; +} + +void st2xxx_device::btclr_all_w(u8 data) +{ + // Only bit 7 has any effect + if (BIT(data, 7)) + m_btsr = 0; +} + +u8 st2xxx_device::sys_r() +{ + return m_sys | 0x01; +} + +void st2xxx_device::sys_w(u8 data) +{ + u8 mask = st2xxx_sys_mask(); + m_sys = data & mask; + if (BIT(mask, 1)) + downcast(*mintf).irr_enable = BIT(data, 1); +} + +u8 st2xxx_device::irrl_r() +{ + return downcast(*mintf).irr & 0xff; +} + +void st2xxx_device::irrl_w(u8 data) +{ + u16 &irr = downcast(*mintf).irr; + irr = (data & m_prr_mask) | (irr & 0xff00); +} + +u8 st2xxx_device::irrh_r() +{ + return downcast(*mintf).irr >> 8; +} + +void st2xxx_device::irrh_w(u8 data) +{ + u16 &irr = downcast(*mintf).irr; + irr = ((u16(data) << 8) & m_prr_mask) | (irr & 0x00ff); +} + +u8 st2xxx_device::prrl_r() +{ + return downcast(*mintf).prr & 0xff; +} + +void st2xxx_device::prrl_w(u8 data) +{ + u16 &prr = downcast(*mintf).prr; + prr = (data & m_prr_mask) | (prr & 0xff00); +} + +u8 st2xxx_device::prrh_r() +{ + return downcast(*mintf).prr >> 8; +} + +void st2xxx_device::prrh_w(u8 data) +{ + u16 &prr = downcast(*mintf).prr; + prr = ((u16(data) << 8) & m_prr_mask) | (prr & 0x00ff); +} + +u8 st2xxx_device::drrl_r() +{ + return downcast(*mintf).drr & 0xff; +} + +void st2xxx_device::drrl_w(u8 data) +{ + u16 &drr = downcast(*mintf).drr; + drr = (data & m_drr_mask) | (drr & 0xff00); +} + +u8 st2xxx_device::drrh_r() +{ + return downcast(*mintf).drr >> 8; +} + +void st2xxx_device::drrh_w(u8 data) +{ + u16 &drr = downcast(*mintf).drr; + drr = ((u16(data) << 8) & m_drr_mask) | (drr & 0x00ff); +} + +u8 st2xxx_device::dmrl_r() +{ + return downcast(*mintf).dmr & 0xff; +} + +void st2xxx_device::dmrl_w(u8 data) +{ + u16 &dmr = downcast(*mintf).dmr; + dmr = (data & m_drr_mask) | (dmr & 0xff00); +} + +u8 st2xxx_device::dmrh_r() +{ + return downcast(*mintf).dmr >> 8; +} + +void st2xxx_device::dmrh_w(u8 data) +{ + u16 &dmr = downcast(*mintf).dmr; + dmr = ((u16(data) << 8) & m_drr_mask) | (dmr & 0x00ff); +} + u8 st2xxx_device::ireql_r() { return m_ireq & 0x00ff; @@ -216,6 +461,11 @@ void st2xxx_device::ireql_w(u8 data) { if ((m_ireq & ~data & 0x00ff) != 0) { + for (int i = 0; i < 8; i++) + { + if (!BIT(data, i) && BIT(m_ireq, i)) + LOGMASKED(LOG_IRQ, "%s interrupt cleared (PC = $%04X)\n", st2xxx_irq_name(i), PPC); + } m_ireq &= data | 0xff00; update_irq_state(); } @@ -230,6 +480,11 @@ void st2xxx_device::ireqh_w(u8 data) { if ((m_ireq & ~(u16(data) << 8) & 0xff00) != 0) { + for (int i = 0; i < 8; i++) + { + if (!BIT(data, i) && BIT(m_ireq, i + 8)) + LOGMASKED(LOG_IRQ, "%s interrupt cleared (PC = $%04X)\n", st2xxx_irq_name(i + 8), PPC); + } m_ireq &= u16(data) << 8 | 0x00ff; update_irq_state(); } @@ -242,8 +497,20 @@ u8 st2xxx_device::ienal_r() void st2xxx_device::ienal_w(u8 data) { - m_iena = (m_iena & 0xff00) | (data & m_ireq_mask); - update_irq_state(); + data &= st2xxx_ireq_mask(); + if (data != (m_iena & 0x00ff)) + { + for (int i = 0; i < 8; i++) + { + if (BIT(data, i) != BIT(m_iena, i)) + LOGMASKED(LOG_IRQ, "%s interrupt %sabled (PC = $%04X)\n", + st2xxx_irq_name(i), + BIT(data, i) ? "en" : "dis", + PPC); + } + m_iena = (m_iena & 0xff00) | data; + update_irq_state(); + } } u8 st2xxx_device::ienah_r() @@ -253,8 +520,20 @@ u8 st2xxx_device::ienah_r() void st2xxx_device::ienah_w(u8 data) { - m_iena = (m_iena & 0x00ff) | ((u16(data) << 8) & m_ireq_mask); - update_irq_state(); + data &= st2xxx_ireq_mask() >> 8; + if (data != (m_iena >> 8)) + { + for (int i = 0; i < 8; i++) + { + if (BIT(data, i) != BIT(m_iena, i + 8)) + LOGMASKED(LOG_IRQ, "%s interrupt %sabled (PC = $%04X)\n", + st2xxx_irq_name(i + 8), + BIT(data, i) ? "en" : "dis", + PPC); + } + m_iena = (m_iena & 0x00ff) | (u16(data) << 8); + update_irq_state(); + } } void st2xxx_device::lssal_w(u8 data) diff --git a/src/devices/cpu/m6502/st2xxx.h b/src/devices/cpu/m6502/st2xxx.h index f35b5e540b3..ad31e73be77 100644 --- a/src/devices/cpu/m6502/st2xxx.h +++ b/src/devices/cpu/m6502/st2xxx.h @@ -32,10 +32,13 @@ public: ST_PFC, ST_PFD, ST_PMCR, + ST_BTEN, + ST_BTSR, ST_SYS, ST_IRR, ST_PRR, ST_DRR, + ST_DMR, ST_IREQ, ST_IENA, ST_LSSA, @@ -60,7 +63,7 @@ public: auto out_pl_callback() { return m_out_port_cb[6].bind(); } protected: - st2xxx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor internal_map, int data_bits, u16 ireq_mask); + st2xxx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor internal_map, int data_bits, bool has_banked_ram); virtual space_config_vector memory_space_config() const override; virtual void device_resolve_objects() override; @@ -69,21 +72,38 @@ protected: virtual void do_exec_full() override; virtual void do_exec_partial() override; + virtual u16 st2xxx_ireq_mask() const = 0; + virtual const char *st2xxx_irq_name(int i) const = 0; + virtual unsigned st2xxx_bt_divider(int n) const = 0; + virtual u8 st2xxx_sys_mask() const = 0; + virtual bool st2xxx_has_dma() const { return false; } + class mi_st2xxx : public memory_interface { public: virtual u8 read_vector(u16 adr) = 0; address_space *data; memory_access_cache<0, 0, ENDIANNESS_LITTLE> *dcache; + bool irq_service; + bool irr_enable; + u16 irr; + u16 prr; + u16 drr; + u16 dmr; }; + void init_base_timer(u16 ireq); + void save_common_registers(); + u8 read_vector(u16 adr) { return downcast(*mintf).read_vector(adr); } void set_irq_service(bool state) { downcast(*mintf).irq_service = state; } void update_irq_state() { irq_state = (m_ireq & m_iena) != 0; } u8 acknowledge_irq(); + TIMER_CALLBACK_MEMBER(bt_interrupt); + u8 pdata_r(offs_t offset); void pdata_w(offs_t offset, u8 data); u8 pctrl_r(offs_t offset); @@ -101,6 +121,32 @@ protected: u8 pfd_r(); void pfd_w(u8 data); + u8 sys_r(); + void sys_w(u8 data); + + u8 irrl_r(); + void irrl_w(u8 data); + u8 irrh_r(); + void irrh_w(u8 data); + u8 prrl_r(); + void prrl_w(u8 data); + u8 prrh_r(); + void prrh_w(u8 data); + u8 drrl_r(); + void drrl_w(u8 data); + u8 drrh_r(); + void drrh_w(u8 data); + u8 dmrl_r(); + void dmrl_w(u8 data); + u8 dmrh_r(); + void dmrh_w(u8 data); + + u8 bten_r(); + void bten_w(u8 data); + u8 btsr_r(); + void btclr_w(u8 data); + void btclr_all_w(u8 data); + u8 ireql_r(); void ireql_w(u8 data); u8 ireqh_r(); @@ -131,15 +177,22 @@ protected: devcb_read8 m_in_port_cb[7]; devcb_write8 m_out_port_cb[7]; + const u16 m_prr_mask; + const u16 m_drr_mask; + u8 m_pdata[7]; u8 m_pctrl[7]; u8 m_psel[7]; u8 m_pfun[2]; u8 m_pmcr; + u8 m_bten; + u8 m_btsr; + emu_timer *m_base_timer[8]; + u8 m_bt_mask; + u16 m_bt_ireq; + u8 m_sys; u16 m_ireq; u16 m_iena; - const u16 m_ireq_mask; - u8 m_sys; u16 m_lssa; u8 m_lvpw; u8 m_lxmax; -- cgit v1.2.3