From d9dcb8831bf150e05889c6a22a2e3331855e4437 Mon Sep 17 00:00:00 2001 From: AJR Date: Sun, 3 Nov 2019 23:52:48 -0500 Subject: [PATCH] st2204: Add rudimentary DMA control (nw) --- src/devices/cpu/m6502/st2204.cpp | 122 ++++++++++++++++++++++++++++++- src/devices/cpu/m6502/st2204.h | 25 ++++++- 2 files changed, 145 insertions(+), 2 deletions(-) diff --git a/src/devices/cpu/m6502/st2204.cpp b/src/devices/cpu/m6502/st2204.cpp index df85fb5d695..3e27a0be555 100644 --- a/src/devices/cpu/m6502/st2204.cpp +++ b/src/devices/cpu/m6502/st2204.cpp @@ -41,6 +41,9 @@ st2204_device::st2204_device(const machine_config &mconfig, const char *tag, dev , m_bten(0) , m_btsr(0) , m_base_timer{0} + , m_dms(0) + , m_dmd(0) + , m_dcnth(0) { } @@ -61,6 +64,7 @@ void st2204_device::device_start() intf->irr = 0; intf->prr = 0; intf->drr = 0; + 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)); @@ -75,6 +79,9 @@ void st2204_device::device_start() save_item(NAME(m_pfun)); save_item(NAME(m_bten)); save_item(NAME(m_btsr)); + 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)); @@ -116,6 +123,9 @@ void st2204_device::device_start() state_add(ST_LVPW, "LVPW", m_lvpw); state_add(ST_LXMAX, "LXMAX", m_lxmax); state_add(ST_LYMAX, "LYMAX", m_lymax); + state_add(ST_DMS, "DMS", m_dms); + state_add(ST_DMR, "DMR", downcast(*mintf).dmr).mask(0x7ff); + state_add(ST_DMD, "DMD", m_dmd); } void st2204_device::device_reset() @@ -127,6 +137,7 @@ void st2204_device::device_reset() m.irr = 0; m.prr = 0; m.drr = 0; + m.dmr = 0; bten_w(0); m_btsr = 0; @@ -180,6 +191,14 @@ u8 st2204_device::mi_st2204::read_arg(u16 adr) return BIT(adr, 15) ? dreadc(adr) : BIT(adr, 14) ? preadc(adr) : cache->read_byte(adr); } +u8 st2204_device::mi_st2204::read_dma(u16 adr) +{ + if (BIT(adr, 15)) + return dcache->read_byte(u32(dmr) << 15 | (adr & 0x7fff)); + else + return read(adr); +} + u8 st2204_device::mi_st2204::read_vector(u16 adr) { return pread(adr); @@ -299,6 +318,98 @@ void st2204_device::drrh_w(u8 data) drr = (data & 0x07) << 16 | (drr & 0x00ff); } +u8 st2204_device::dmsl_r() +{ + return m_dms & 0xff; +} + +void st2204_device::dmsl_w(u8 data) +{ + m_dms = (m_dms & 0xff00) | data; +} + +u8 st2204_device::dmsh_r() +{ + return m_dms >> 8; +} + +void st2204_device::dmsh_w(u8 data) +{ + m_dms = (m_dms & 0x00ff) | u16(data) << 8; +} + +u8 st2204_device::dmdl_r() +{ + return m_dmd & 0xff; +} + +void st2204_device::dmdl_w(u8 data) +{ + m_dmd = (m_dmd & 0xff00) | data; +} + +u8 st2204_device::dmdh_r() +{ + return m_dmd >> 8; +} + +void st2204_device::dmdh_w(u8 data) +{ + m_dmd = (m_dmd & 0x00ff) | u16(data) << 8; +} + +void st2204_device::dcntl_w(u8 data) +{ + u16 count = data | u16(m_dcnth & 0x0f) << 8; + + // FIXME: not instantaneous (obviously), but takes 2 cycles per transfer while CPU is halted + mi_st2204 &intf = downcast(*mintf); + while (count != 0xffff) + { + intf.write(m_dmd, intf.read_dma(m_dms)); + + if (m_dms++ == 0xffff) + { + // DMR bank increments automatically when source is in data memory + m_dms = 0x8000; + intf.dmr = (intf.dmr + 1) & 0x7ff; + } + + // DMAM inhibits destination increment + if (!BIT(m_dcnth, 4)) + m_dmd++; + + count--; + } +} + +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) << 16 | (dmr & 0x00ff); +} + u8 st2204_device::pmem_r(offs_t offset) { return downcast(*mintf).pread(offset); @@ -329,12 +440,21 @@ void st2204_device::int_map(address_map &map) 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)); + // 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)); + map(0x002a, 0x002a).rw(FUNC(st2204_device::dmdl_r), FUNC(st2204_device::dmdl_w)); + map(0x002b, 0x002b).rw(FUNC(st2204_device::dmdh_r), FUNC(st2204_device::dmdh_w)); + 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(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)); map(0x0035, 0x0035).rw(FUNC(st2204_device::drrh_r), FUNC(st2204_device::drrh_w)); + map(0x0036, 0x0036).rw(FUNC(st2204_device::dmrl_r), FUNC(st2204_device::dmrl_w)); + map(0x0037, 0x0037).rw(FUNC(st2204_device::dmrh_r), FUNC(st2204_device::dmrh_w)); map(0x003c, 0x003c).rw(FUNC(st2204_device::ireql_r), FUNC(st2204_device::ireql_w)); map(0x003d, 0x003d).rw(FUNC(st2204_device::ireqh_r), FUNC(st2204_device::ireqh_w)); map(0x003e, 0x003e).rw(FUNC(st2204_device::ienal_r), FUNC(st2204_device::ienal_w)); @@ -346,7 +466,7 @@ void st2204_device::int_map(address_map &map) map(0x0044, 0x0044).rw(FUNC(st2204_device::lymax_r), FUNC(st2204_device::lymax_w)); map(0x004c, 0x004c).rw(FUNC(st2204_device::pl_r), FUNC(st2204_device::pl_w)); map(0x004e, 0x004e).w(FUNC(st2204_device::pcl_w)); - map(0x0080, 0x287f).ram(); + map(0x0080, 0x287f).ram(); // 2800-287F possibly not present in earlier versions map(0x4000, 0x7fff).rw(FUNC(st2204_device::pmem_r), FUNC(st2204_device::pmem_w)); map(0x8000, 0xffff).rw(FUNC(st2204_device::dmem_r), FUNC(st2204_device::dmem_w)); } diff --git a/src/devices/cpu/m6502/st2204.h b/src/devices/cpu/m6502/st2204.h index d88825a8b7f..63ef404ea48 100644 --- a/src/devices/cpu/m6502/st2204.h +++ b/src/devices/cpu/m6502/st2204.h @@ -18,7 +18,10 @@ class st2204_device : public st2xxx_device public: enum { ST_BTEN = ST_LYMAX + 1, - ST_BTSR + ST_BTSR, + ST_DMS, + ST_DMD, + ST_DMR }; st2204_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); @@ -33,6 +36,7 @@ private: virtual u8 read(u16 adr) override; virtual u8 read_sync(u16 adr) override; virtual u8 read_arg(u16 adr) override; + u8 read_dma(u16 adr); virtual u8 read_vector(u16 adr) override; virtual void write(u16 adr, u8 val) override; @@ -47,6 +51,7 @@ private: u8 irr; u16 prr; u16 drr; + u16 dmr; }; template TIMER_CALLBACK_MEMBER(bt_interrupt); @@ -69,6 +74,20 @@ private: void bten_w(u8 data); u8 btsr_r(); void btsr_w(u8 data); + u8 dmsl_r(); + void dmsl_w(u8 data); + u8 dmsh_r(); + void dmsh_w(u8 data); + u8 dmdl_r(); + void dmdl_w(u8 data); + u8 dmdh_r(); + 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); @@ -80,6 +99,10 @@ private: u8 m_bten; u8 m_btsr; emu_timer *m_base_timer[5]; + + u16 m_dms; + u16 m_dmd; + u8 m_dcnth; }; DECLARE_DEVICE_TYPE(ST2204, st2204_device)