summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2019-11-03 11:30:14 -0500
committer AJR <ajrhacker@users.noreply.github.com>2019-11-03 11:32:32 -0500
commit27ddae4ecfaef153a184341cd5432f370d20c697 (patch)
tree62de06d2a1986db84f4ef672f0a7e72bb26409b1 /src/devices/cpu
parent7791be49e4819855d52c5037cdf976ee37c40b14 (diff)
Preliminary SoC emulation for Sitronix ST2204 and ST2205U
Diffstat (limited to 'src/devices/cpu')
-rw-r--r--src/devices/cpu/m6502/dst2xxx.lst20
-rw-r--r--src/devices/cpu/m6502/ost2xxx.lst58
-rw-r--r--src/devices/cpu/m6502/st2204.cpp276
-rw-r--r--src/devices/cpu/m6502/st2204.h72
-rw-r--r--src/devices/cpu/m6502/st2205u.cpp400
-rw-r--r--src/devices/cpu/m6502/st2205u.h97
-rw-r--r--src/devices/cpu/m6502/st2xxx.cpp252
-rw-r--r--src/devices/cpu/m6502/st2xxx.h134
8 files changed, 1309 insertions, 0 deletions
diff --git a/src/devices/cpu/m6502/dst2xxx.lst b/src/devices/cpu/m6502/dst2xxx.lst
new file mode 100644
index 00000000000..e9687ba68f9
--- /dev/null
+++ b/src/devices/cpu/m6502/dst2xxx.lst
@@ -0,0 +1,20 @@
+# license:BSD-3-Clause
+# copyright-holders:Olivier Galibert
+# almost identical to r65c02
+brk_st_imp ora_idx nop_imm nop_c_imp tsb_zpg ora_zpg asl_c_zpg rmb_bzp php_imp ora_imm asl_acc nop_c_imp tsb_aba ora_aba asl_c_aba bbr_zpb
+bpl_rel ora_idy ora_zpi nop_c_imp trb_zpg ora_zpx asl_c_zpx rmb_bzp clc_imp ora_aby inc_acc nop_c_imp trb_aba ora_abx asl_c_abx bbr_zpb
+jsr_adr and_idx nop_imm nop_c_imp bit_zpg and_zpg rol_c_zpg rmb_bzp plp_imp and_imm rol_acc nop_c_imp bit_aba and_aba rol_c_aba bbr_zpb
+bmi_rel and_idy and_zpi nop_c_imp bit_zpx and_zpx rol_c_zpx rmb_bzp sec_imp and_aby dec_acc nop_c_imp bit_abx and_abx rol_c_abx bbr_zpb
+rti_st_imp eor_idx nop_imm nop_c_imp nop_zpg eor_zpg lsr_c_zpg rmb_bzp pha_imp eor_imm lsr_acc nop_c_imp jmp_adr eor_aba lsr_c_aba bbr_zpb
+bvc_rel eor_idy eor_zpi nop_c_imp nop_zpx eor_zpx lsr_c_zpx rmb_bzp cli_imp eor_aby phy_imp nop_c_imp nop_c_aba eor_abx lsr_c_abx bbr_zpb
+rts_imp adc_c_idx nop_imm nop_c_imp stz_zpg adc_c_zpg ror_c_zpg rmb_bzp pla_imp adc_c_imm ror_acc nop_c_imp jmp_c_ind adc_c_aba ror_c_aba bbr_zpb
+bvs_rel adc_c_idy adc_c_zpi nop_c_imp stz_zpx adc_c_zpx ror_c_zpx rmb_bzp sei_imp adc_c_aby ply_imp nop_c_imp jmp_iax adc_c_abx ror_c_abx bbr_zpb
+bra_rel sta_idx nop_imm nop_c_imp sty_zpg sta_zpg stx_zpg smb_bzp dey_imp bit_imm txa_imp nop_c_imp sty_aba sta_aba stx_aba bbs_zpb
+bcc_rel sta_idy sta_zpi nop_c_imp sty_zpx sta_zpx stx_zpy smb_bzp tya_imp sta_aby txs_imp nop_c_imp stz_aba sta_abx stz_abx bbs_zpb
+ldy_imm lda_idx ldx_imm nop_c_imp ldy_zpg lda_zpg ldx_zpg smb_bzp tay_imp lda_imm tax_imp nop_c_imp ldy_aba lda_aba ldx_aba bbs_zpb
+bcs_rel lda_idy lda_zpi nop_c_imp ldy_zpx lda_zpx ldx_zpy smb_bzp clv_imp lda_aby tsx_imp nop_c_imp ldy_abx lda_abx ldx_aby bbs_zpb
+cpy_imm cmp_idx nop_imm nop_c_imp cpy_zpg cmp_zpg dec_c_zpg smb_bzp iny_imp cmp_imm dex_imp wai_imp cpy_aba cmp_aba dec_c_aba bbs_zpb
+bne_rel cmp_idy cmp_zpi nop_c_imp nop_zpx cmp_zpx dec_c_zpx smb_bzp cld_imp cmp_aby phx_imp stp_imp nop_c_abx cmp_abx dec_c_abx bbs_zpb
+cpx_imm sbc_c_idx nop_imm nop_c_imp cpx_zpg sbc_c_zpg inc_c_zpg smb_bzp inx_imp sbc_c_imm nop_imp nop_c_imp cpx_aba sbc_c_aba inc_c_aba bbs_zpb
+beq_rel sbc_c_idy sbc_c_zpi nop_c_imp nop_zpx sbc_c_zpx inc_c_zpx smb_bzp sed_imp sbc_c_aby plx_imp nop_c_imp nop_c_abx sbc_c_abx inc_c_abx bbs_zpb
+reset_st
diff --git a/src/devices/cpu/m6502/ost2xxx.lst b/src/devices/cpu/m6502/ost2xxx.lst
new file mode 100644
index 00000000000..9b30c2e9b05
--- /dev/null
+++ b/src/devices/cpu/m6502/ost2xxx.lst
@@ -0,0 +1,58 @@
+# license:BSD-3-Clause
+# copyright-holders:Olivier Galibert
+# m65c02 opcodes, with a twist
+
+brk_st_imp
+ if(irq_taken || nmi_state) {
+ read_pc_noinc();
+ } else {
+ read_pc();
+ }
+ write(SP, PC >> 8);
+ dec_SP();
+ write(SP, PC);
+ dec_SP();
+ write(SP, irq_taken || nmi_state ? P & ~F_B : P);
+ dec_SP();
+ set_irq_service(true);
+ if(irq_taken && nmi_state) { // NMI is not present on actual parts
+ PC = read_vector(0x7ffa);
+ PC = set_h(PC, read_vector(0x7ffb));
+ nmi_state = false;
+ } else if(irq_taken) {
+ TMP = acknowledge_irq();
+ PC = read_vector(0x7ff8 - (TMP << 1));
+ PC = set_h(PC, read_vector(0x7ff9 - (TMP << 1)));
+ } else {
+ PC = read_vector(0x7ffe);
+ PC = set_h(PC, read_vector(0x7fff));
+ }
+ irq_taken = false;
+ P = (P | F_I) & ~F_D; // Do *not* move after the prefetch
+ prefetch();
+ inst_state = -1;
+
+rti_st_imp
+ read_pc_noinc();
+ read(SP);
+ inc_SP();
+ P = read(SP) | (F_B|F_E);
+ inc_SP();
+ PC = read(SP);
+ inc_SP();
+ PC = set_h(PC, read(SP));
+ set_irq_service(false);
+ prefetch();
+
+reset_st
+ read_arg(0xffff);
+ read_pc_noinc();
+ read(SP); dec_SP();
+ read(SP); dec_SP();
+ read(SP); dec_SP();
+ P = (P | F_I) & ~F_D;
+ set_irq_service(false);
+ PC = read_vector(0x7ffc);
+ PC = set_h(PC, read_vector(0x7ffd));
+ prefetch();
+ inst_state = -1;
diff --git a/src/devices/cpu/m6502/st2204.cpp b/src/devices/cpu/m6502/st2204.cpp
new file mode 100644
index 00000000000..7f70fd70b89
--- /dev/null
+++ b/src/devices/cpu/m6502/st2204.cpp
@@ -0,0 +1,276 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Sitronix ST2204 8-Bit Integrated Microcontroller
+
+ Functional blocks:
+ * Interrupt controller (11 levels excluding BRK and RESET)
+ * GPIO (6 ports, 8 bits each)
+ * External bus (up to 7 CS outputs, 48M maximum addressable)
+ * Timers/event counters with clocking outputs (2 plus base timer)
+ * Programmable sound generator (2 channels plus DAC)
+ * LCD controller (320x240 B/W or 240x160 4-gray)
+ * Serial peripheral interface
+ * UART (built-in BRG; RS-232 and IrDA modes)
+ * Direct memory access
+ * Power down modes (WAI-0, WAI-1, STP)
+ * Watchdog timer
+ * Low voltage detector
+ * 512K ROM (may be disabled)
+ * 10K RAM
+
+ Emulation is largely based on documentation for the ST2202, which
+ has similar though somewhat lesser capabilities.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "st2204.h"
+
+DEFINE_DEVICE_TYPE(ST2204, st2204_device, "st2204", "Sitronix ST2204 Integrated Microcontroller")
+
+st2204_device::st2204_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : 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)
+{
+}
+
+void st2204_device::device_start()
+{
+ std::unique_ptr<mi_st2204> intf = std::make_unique<mi_st2204>();
+ intf->data = &space(AS_DATA);
+ intf->dcache = space(AS_DATA).cache<0, 0, ENDIANNESS_LITTLE>();
+ intf->irr_enable = false;
+ intf->irr = 0;
+ intf->prr = 0;
+ intf->drr = 0;
+ intf->irq_service = false;
+
+ save_item(NAME(m_pdata));
+ save_item(NAME(m_pctrl));
+ save_item(NAME(m_psel));
+ save_item(NAME(m_pfun));
+ save_item(NAME(m_sys));
+ save_item(NAME(m_pmcr));
+ save_item(NAME(m_ireq));
+ save_item(NAME(m_iena));
+ 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);
+ init();
+
+ state_add(ST_IRR, "IRR", downcast<mi_st2204 &>(*mintf).irr).mask(0xff);
+ state_add(ST_PRR, "PRR", downcast<mi_st2204 &>(*mintf).prr).mask(0xfff);
+ state_add(ST_DRR, "DRR", downcast<mi_st2204 &>(*mintf).drr).mask(0x7ff);
+ state_add<u8>(ST_IREQ, "IREQ", [this]() { return m_ireq; }, [this](u16 data) { m_ireq = data; update_irq_state(); }).mask(m_ireq_mask);
+ state_add<u8>(ST_IENA, "IENA", [this]() { return m_iena; }, [this](u16 data) { m_iena = data; update_irq_state(); }).mask(m_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]);
+ state_add(ST_PCA + i, string_format("PC%c", 'A' + i).c_str(), m_pctrl[i]);
+ if (i == 2)
+ state_add(ST_PSA + i, string_format("PS%c", 'A' + i).c_str(), m_psel[i]);
+ if (i == 2 || i == 3)
+ state_add(ST_PFC + i - 2, string_format("PF%c", 'A' + i).c_str(), m_pfun[i - 2]);
+ }
+ state_add(ST_PDL, "PDL", m_pdata[6]);
+ state_add(ST_PCL, "PCL", m_pctrl[6]);
+ state_add(ST_PMCR, "PMCR", m_pmcr);
+ state_add<u8>(ST_SYS, "SYS", [this]() { return m_sys; }, [this](u8 data) { sys_w(data); });
+}
+
+void st2204_device::device_reset()
+{
+ st2xxx_device::device_reset();
+
+ mi_st2204 &m = downcast<mi_st2204 &>(*mintf);
+ m.irr_enable = false;
+ m.irr = 0;
+ m.prr = 0;
+ m.drr = 0;
+}
+
+u8 st2204_device::mi_st2204::pread(u16 adr)
+{
+ u16 bank = irq_service && irr_enable ? irr : prr;
+ return data->read_byte(u32(bank ^ 1) << 14 | (adr & 0x3fff));
+}
+
+u8 st2204_device::mi_st2204::preadc(u16 adr)
+{
+ u16 bank = irq_service && irr_enable ? irr : prr;
+ return dcache->read_byte(u32(bank ^ 1) << 14 | (adr & 0x3fff));
+}
+
+void st2204_device::mi_st2204::pwrite(u16 adr, u8 val)
+{
+ u16 bank = irq_service && irr_enable ? irr : prr;
+ data->write_byte(u32(bank ^ 1) << 14 | (adr & 0x3fff), val);
+}
+
+u8 st2204_device::mi_st2204::dread(u16 adr)
+{
+ return data->read_byte(u32(drr) << 15 | (adr & 0x7fff));
+}
+
+u8 st2204_device::mi_st2204::dreadc(u16 adr)
+{
+ return dcache->read_byte(u32(drr) << 15 | (adr & 0x7fff));
+}
+
+void st2204_device::mi_st2204::dwrite(u16 adr, u8 val)
+{
+ data->write_byte(u32(drr) << 15 | (adr & 0x7fff), val);
+}
+
+u8 st2204_device::mi_st2204::read(u16 adr)
+{
+ return program->read_byte(adr);
+}
+
+u8 st2204_device::mi_st2204::read_sync(u16 adr)
+{
+ return BIT(adr, 15) ? dreadc(adr) : BIT(adr, 14) ? preadc(adr) : cache->read_byte(adr);
+}
+
+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_vector(u16 adr)
+{
+ return pread(adr);
+}
+
+void st2204_device::mi_st2204::write(u16 adr, u8 val)
+{
+ program->write_byte(adr, val);
+}
+
+u8 st2204_device::pmcr_r()
+{
+ return m_pmcr;
+}
+
+void st2204_device::pmcr_w(u8 data)
+{
+ m_pmcr = data;
+}
+
+u8 st2204_device::sys_r()
+{
+ return m_sys | 0x01;
+}
+
+void st2204_device::sys_w(u8 data)
+{
+ m_sys = data;
+ downcast<mi_st2204 &>(*mintf).irr_enable = BIT(data, 2);
+}
+
+u8 st2204_device::irr_r()
+{
+ return downcast<mi_st2204 &>(*mintf).irr;
+}
+
+void st2204_device::irr_w(u8 data)
+{
+ downcast<mi_st2204 &>(*mintf).irr = data;
+}
+
+u8 st2204_device::prrl_r()
+{
+ return downcast<mi_st2204 &>(*mintf).prr & 0xff;
+}
+
+void st2204_device::prrl_w(u8 data)
+{
+ u16 &prr = downcast<mi_st2204 &>(*mintf).prr;
+ prr = data | (prr & 0x0f00);
+}
+
+u8 st2204_device::prrh_r()
+{
+ return downcast<mi_st2204 &>(*mintf).prr >> 8;
+}
+
+void st2204_device::prrh_w(u8 data)
+{
+ u16 &prr = downcast<mi_st2204 &>(*mintf).prr;
+ prr = (data & 0x0f) << 16 | (prr & 0x00ff);
+}
+
+u8 st2204_device::drrl_r()
+{
+ return downcast<mi_st2204 &>(*mintf).drr & 0xff;
+}
+
+void st2204_device::drrl_w(u8 data)
+{
+ u16 &drr = downcast<mi_st2204 &>(*mintf).drr;
+ drr = data | (drr & 0x0700);
+}
+
+u8 st2204_device::drrh_r()
+{
+ return downcast<mi_st2204 &>(*mintf).drr >> 8;
+}
+
+void st2204_device::drrh_w(u8 data)
+{
+ u16 &drr = downcast<mi_st2204 &>(*mintf).drr;
+ drr = (data & 0x07) << 16 | (drr & 0x00ff);
+}
+
+u8 st2204_device::pmem_r(offs_t offset)
+{
+ return downcast<mi_st2204 &>(*mintf).pread(offset);
+}
+
+void st2204_device::pmem_w(offs_t offset, u8 data)
+{
+ downcast<mi_st2204 &>(*mintf).pwrite(offset, data);
+}
+
+u8 st2204_device::dmem_r(offs_t offset)
+{
+ return downcast<mi_st2204 &>(*mintf).dread(offset);
+}
+
+void st2204_device::dmem_w(offs_t offset, u8 data)
+{
+ downcast<mi_st2204 &>(*mintf).dwrite(offset, data);
+}
+
+void st2204_device::int_map(address_map &map)
+{
+ map(0x0000, 0x0004).rw(FUNC(st2204_device::pdata_r), FUNC(st2204_device::pdata_w));
+ map(0x0005, 0x0005).rw(FUNC(st2204_device::psc_r), FUNC(st2204_device::psc_w));
+ map(0x0008, 0x000c).rw(FUNC(st2204_device::pdata_r), FUNC(st2204_device::pdata_w));
+ map(0x000d, 0x000d).rw(FUNC(st2204_device::pfc_r), FUNC(st2204_device::pfc_w));
+ 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(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(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));
+ map(0x003f, 0x003f).rw(FUNC(st2204_device::ienah_r), FUNC(st2204_device::ienah_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, 0x27ff).ram(); // 10K internal SRAM; extent of mapping guessed
+ 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
new file mode 100644
index 00000000000..4ec61636d65
--- /dev/null
+++ b/src/devices/cpu/m6502/st2204.h
@@ -0,0 +1,72 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Sitronix ST2204 8-Bit Integrated Microcontroller
+
+**********************************************************************/
+
+#ifndef MAME_CPU_M6502_ST2204_H
+#define MAME_CPU_M6502_ST2204_H
+
+#pragma once
+
+#include "st2xxx.h"
+
+class st2204_device : public st2xxx_device
+{
+public:
+ st2204_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ class mi_st2204 : public mi_st2xxx {
+ public:
+ virtual u8 read(u16 adr) override;
+ virtual u8 read_sync(u16 adr) override;
+ virtual u8 read_arg(u16 adr) override;
+ virtual u8 read_vector(u16 adr) override;
+ virtual void write(u16 adr, u8 val) override;
+
+ u8 pread(u16 adr);
+ u8 preadc(u16 adr);
+ void pwrite(u16 adr, u8 val);
+ u8 dread(u16 adr);
+ u8 dreadc(u16 adr);
+ void dwrite(u16 adr, u8 val);
+
+ bool irr_enable;
+ u8 irr;
+ u16 prr;
+ u16 drr;
+ };
+
+ 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 pmem_r(offs_t offset);
+ void pmem_w(offs_t offset, u8 data);
+ u8 dmem_r(offs_t offset);
+ void dmem_w(offs_t offset, u8 data);
+
+ void int_map(address_map &map);
+};
+
+DECLARE_DEVICE_TYPE(ST2204, st2204_device)
+
+#endif // MAME_MACHINE_M6502_ST2204_H
diff --git a/src/devices/cpu/m6502/st2205u.cpp b/src/devices/cpu/m6502/st2205u.cpp
new file mode 100644
index 00000000000..7084eb632c4
--- /dev/null
+++ b/src/devices/cpu/m6502/st2205u.cpp
@@ -0,0 +1,400 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Sitronix ST2205U 8-Bit Integrated Microcontroller
+
+ Functional blocks:
+ * Interrupt controller (15 levels excluding BRK and RESET)
+ * GPIO (7 ports, 8 bits each)
+ * External bus (up to 7 CS outputs, 48M maximum addressable)
+ * Timers/event counters with clocking outputs (4 plus base timer)
+ * Programmable sound generator (4 channels with FIFOs, plus PWM
+ or ADPCM DAC and 16x8 signed multiplicator)
+ * LCD controller (640x400 B/W, 400x320 4-gray, 160xRGBx120 16-gray)
+ * Serial peripheral interface
+ * UART (built-in BRG; RS-232 and IrDA modes)
+ * USB 1.1 (separate control and bulk transfer endpoint buffers)
+ * Direct memory access
+ * NAND/AND Flash memory interface (includes ECC generator)
+ * Power down modes (WAI-0, WAI-1, STP)
+ * Watchdog timer
+ * Real time clock (seconds, minutes, hours with alarm interrupts)
+ * Low voltage detector with reset
+ * 512K ROM (may be disabled)
+ * 32K SRAM
+
+**********************************************************************/
+
+#include "emu.h"
+#include "st2205u.h"
+
+DEFINE_DEVICE_TYPE(ST2205U, st2205u_device, "st2205", "Sitronix ST2205U Integrated Microcontroller")
+
+st2205u_device::st2205u_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : 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_lvctr(0)
+{
+}
+
+void st2205u_device::device_start()
+{
+ std::unique_ptr<mi_st2205u> intf = std::make_unique<mi_st2205u>();
+ intf->data = &space(AS_DATA);
+ intf->dcache = space(AS_DATA).cache<0, 0, ENDIANNESS_LITTLE>();
+ intf->irr_enable = false;
+ intf->irr = 0;
+ intf->prr = 0;
+ intf->drr = 0;
+ intf->brr = 0;
+ intf->irq_service = false;
+
+ intf->ram = make_unique_clear<u8[]>(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_sys));
+ save_item(NAME(m_pmcr));
+ save_item(NAME(m_ireq));
+ save_item(NAME(m_iena));
+ 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);
+ init();
+
+ state_add(ST_IRR, "IRR", downcast<mi_st2205u &>(*mintf).irr).mask(0x87ff);
+ state_add(ST_PRR, "PRR", downcast<mi_st2205u &>(*mintf).prr).mask(0x87ff);
+ state_add(ST_DRR, "DRR", downcast<mi_st2205u &>(*mintf).drr).mask(0x8fff);
+ state_add(ST_BRR, "BRR", downcast<mi_st2205u &>(*mintf).brr).mask(0x9fff);
+ state_add<u8>(ST_IREQ, "IREQ", [this]() { return m_ireq; }, [this](u16 data) { m_ireq = data; update_irq_state(); }).mask(m_ireq_mask);
+ state_add<u8>(ST_IENA, "IENA", [this]() { return m_iena; }, [this](u16 data) { m_iena = data; update_irq_state(); }).mask(m_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]);
+ state_add(ST_PCA + i, string_format("PC%c", 'A' + i).c_str(), m_pctrl[i]);
+ if (i == 2 || i == 4)
+ state_add(ST_PSA + i, string_format("PS%c", 'A' + i).c_str(), m_psel[i]);
+ if (i == 2 || i == 3)
+ state_add(ST_PFC + i - 2, string_format("PF%c", 'A' + i).c_str(), m_pfun[i - 2]).mask(i == 2 ? 0xfe : 0xff);
+ }
+ state_add(ST_PDL, "PDL", m_pdata[6]);
+ state_add(ST_PCL, "PCL", m_pctrl[6]);
+ state_add(ST_PMCR, "PMCR", m_pmcr);
+ state_add<u8>(ST_SYS, "SYS", [this]() { return m_sys; }, [this](u8 data) { sys_w(data); }).mask(0xfe);
+ state_add(ST_LVCTR, "LVCTR", m_lvctr).mask(0x0f);
+}
+
+void st2205u_device::device_reset()
+{
+ st2xxx_device::device_reset();
+
+ mi_st2205u &m = downcast<mi_st2205u &>(*mintf);
+ m.irr_enable = false;
+ m.irr = 0;
+ m.prr = 0;
+ m.drr = 0;
+
+ m_lvctr = 0;
+}
+
+u8 st2205u_device::mi_st2205u::pread(u16 adr)
+{
+ u16 bank = irq_service ? irr : prr;
+ if (BIT(bank, 15))
+ return ram[0x4000 | (adr & 0x3fff)];
+ else
+ return data->read_byte(u32(bank) << 14 | (adr & 0x3fff));
+}
+
+u8 st2205u_device::mi_st2205u::preadc(u16 adr)
+{
+ u16 bank = irq_service ? irr : prr;
+ if (BIT(bank, 15))
+ return ram[0x4000 | (adr & 0x3fff)];
+ else
+ return dcache->read_byte(u32(bank) << 14 | (adr & 0x3fff));
+}
+
+void st2205u_device::mi_st2205u::pwrite(u16 adr, u8 val)
+{
+ u16 bank = irq_service ? irr : prr;
+ if (BIT(bank, 15))
+ ram[0x4000 | (adr & 0x3fff)] = val;
+ else
+ data->write_byte(u32(bank) << 14 | (adr & 0x3fff), val);
+}
+
+u8 st2205u_device::mi_st2205u::dread(u16 adr)
+{
+ if (BIT(drr, 15))
+ return ram[adr & 0x7fff];
+ else
+ return data->read_byte(u32(drr) << 15 | (adr & 0x7fff));
+}
+
+u8 st2205u_device::mi_st2205u::dreadc(u16 adr)
+{
+ if (BIT(drr, 15))
+ return ram[adr & 0x7fff];
+ else
+ return dcache->read_byte(u32(drr) << 15 | (adr & 0x7fff));
+}
+
+void st2205u_device::mi_st2205u::dwrite(u16 adr, u8 val)
+{
+ if (BIT(drr, 15))
+ ram[adr & 0x7fff] = val;
+ else
+ data->write_byte(u32(drr) << 15 | (adr & 0x7fff), val);
+}
+
+u8 st2205u_device::mi_st2205u::bread(u16 adr)
+{
+ if (BIT(brr, 15))
+ return ram[0x2000 | (adr & 0x1fff)];
+ else
+ return data->read_byte(u32(brr) << 13 | (adr & 0x1fff));
+}
+
+u8 st2205u_device::mi_st2205u::breadc(u16 adr)
+{
+ if (BIT(brr, 15))
+ return ram[0x2000 | (adr & 0x1fff)];
+ else
+ return dcache->read_byte(u32(brr) << 13 | (adr & 0x1fff));
+}
+
+void st2205u_device::mi_st2205u::bwrite(u16 adr, u8 val)
+{
+ if (BIT(brr, 15))
+ ram[0x2000 | (adr & 0x1fff)] = val;
+ else
+ data->write_byte(u32(brr) << 13 | (adr & 0x1fff), val);
+}
+
+u8 st2205u_device::mi_st2205u::read(u16 adr)
+{
+ return program->read_byte(adr);
+}
+
+u8 st2205u_device::mi_st2205u::read_sync(u16 adr)
+{
+ return BIT(adr, 15) ? dreadc(adr) : BIT(adr, 14) ? preadc(adr) : BIT(adr, 13) ? breadc(adr) : cache->read_byte(adr);
+}
+
+u8 st2205u_device::mi_st2205u::read_arg(u16 adr)
+{
+ return BIT(adr, 15) ? dreadc(adr) : BIT(adr, 14) ? preadc(adr) : BIT(adr, 13) ? breadc(adr) : cache->read_byte(adr);
+}
+
+u8 st2205u_device::mi_st2205u::read_vector(u16 adr)
+{
+ return pread(adr);
+}
+
+void st2205u_device::mi_st2205u::write(u16 adr, u8 val)
+{
+ program->write_byte(adr, val);
+}
+
+u8 st2205u_device::irrl_r()
+{
+ return downcast<mi_st2205u &>(*mintf).irr & 0xff;
+}
+
+void st2205u_device::irrl_w(u8 data)
+{
+ u16 &irr = downcast<mi_st2205u &>(*mintf).irr;
+ irr = data | (irr & 0x8f00);
+}
+
+u8 st2205u_device::irrh_r()
+{
+ return downcast<mi_st2205u &>(*mintf).irr >> 8;
+}
+
+void st2205u_device::irrh_w(u8 data)
+{
+ u16 &irr = downcast<mi_st2205u &>(*mintf).irr;
+ irr = (data & 0x8f) << 16 | (irr & 0x00ff);
+}
+
+u8 st2205u_device::prrl_r()
+{
+ return downcast<mi_st2205u &>(*mintf).prr & 0xff;
+}
+
+void st2205u_device::prrl_w(u8 data)
+{
+ u16 &prr = downcast<mi_st2205u &>(*mintf).prr;
+ prr = data | (prr & 0x8f00);
+}
+
+u8 st2205u_device::prrh_r()
+{
+ return downcast<mi_st2205u &>(*mintf).prr >> 8;
+}
+
+void st2205u_device::prrh_w(u8 data)
+{
+ u16 &prr = downcast<mi_st2205u &>(*mintf).prr;
+ prr = (data & 0x8f) << 16 | (prr & 0x00ff);
+}
+
+u8 st2205u_device::drrl_r()
+{
+ return downcast<mi_st2205u &>(*mintf).drr & 0xff;
+}
+
+void st2205u_device::drrl_w(u8 data)
+{
+ u16 &drr = downcast<mi_st2205u &>(*mintf).drr;
+ drr = data | (drr & 0x8700);
+}
+
+u8 st2205u_device::drrh_r()
+{
+ return downcast<mi_st2205u &>(*mintf).drr >> 8;
+}
+
+void st2205u_device::drrh_w(u8 data)
+{
+ u16 &drr = downcast<mi_st2205u &>(*mintf).drr;
+ drr = (data & 0x87) << 16 | (drr & 0x00ff);
+}
+
+u8 st2205u_device::brrl_r()
+{
+ return downcast<mi_st2205u &>(*mintf).brr & 0xff;
+}
+
+void st2205u_device::brrl_w(u8 data)
+{
+ u16 &brr = downcast<mi_st2205u &>(*mintf).brr;
+ brr = data | (brr & 0x9f00);
+}
+
+u8 st2205u_device::brrh_r()
+{
+ return downcast<mi_st2205u &>(*mintf).brr >> 8;
+}
+
+void st2205u_device::brrh_w(u8 data)
+{
+ u16 &brr = downcast<mi_st2205u &>(*mintf).brr;
+ brr = (data & 0x9f) << 16 | (brr & 0x00ff);
+}
+
+u8 st2205u_device::pmcr_r()
+{
+ return m_pmcr;
+}
+
+void st2205u_device::pmcr_w(u8 data)
+{
+ m_pmcr = data;
+}
+
+u8 st2205u_device::sys_r()
+{
+ return m_sys;
+}
+
+void st2205u_device::sys_w(u8 data)
+{
+ m_sys = data & 0xfe;
+ downcast<mi_st2205u &>(*mintf).irr_enable = BIT(data, 2);
+}
+
+u8 st2205u_device::lvctr_r()
+{
+ return m_lvctr | 0x01;
+}
+
+void st2205u_device::lvctr_w(u8 data)
+{
+ m_lvctr = data & 0x0f;
+}
+
+u8 st2205u_device::ram_r(offs_t offset)
+{
+ return downcast<mi_st2205u &>(*mintf).ram[0x0080 + offset];
+}
+
+void st2205u_device::ram_w(offs_t offset, u8 data)
+{
+ downcast<mi_st2205u &>(*mintf).ram[0x0080 + offset] = data;
+}
+
+u8 st2205u_device::pmem_r(offs_t offset)
+{
+ return downcast<mi_st2205u &>(*mintf).pread(offset);
+}
+
+void st2205u_device::pmem_w(offs_t offset, u8 data)
+{
+ downcast<mi_st2205u &>(*mintf).pwrite(offset, data);
+}
+
+u8 st2205u_device::dmem_r(offs_t offset)
+{
+ return downcast<mi_st2205u &>(*mintf).dread(offset);
+}
+
+void st2205u_device::dmem_w(offs_t offset, u8 data)
+{
+ downcast<mi_st2205u &>(*mintf).dwrite(offset, data);
+}
+
+u8 st2205u_device::bmem_r(offs_t offset)
+{
+ return downcast<mi_st2205u &>(*mintf).bread(offset);
+}
+
+void st2205u_device::bmem_w(offs_t offset, u8 data)
+{
+ downcast<mi_st2205u &>(*mintf).bwrite(offset, data);
+}
+
+void st2205u_device::int_map(address_map &map)
+{
+ map(0x0000, 0x0005).rw(FUNC(st2205u_device::pdata_r), FUNC(st2205u_device::pdata_w));
+ map(0x0006, 0x0006).rw(FUNC(st2205u_device::psc_r), FUNC(st2205u_device::psc_w));
+ map(0x0007, 0x0007).rw(FUNC(st2205u_device::pse_r), FUNC(st2205u_device::pse_w));
+ map(0x0008, 0x000d).rw(FUNC(st2205u_device::pctrl_r), FUNC(st2205u_device::pctrl_w));
+ 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(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));
+ map(0x0032, 0x0032).rw(FUNC(st2205u_device::prrl_r), FUNC(st2205u_device::prrl_w));
+ map(0x0033, 0x0033).rw(FUNC(st2205u_device::prrh_r), FUNC(st2205u_device::prrh_w));
+ map(0x0034, 0x0034).rw(FUNC(st2205u_device::drrl_r), FUNC(st2205u_device::drrl_w));
+ map(0x0035, 0x0035).rw(FUNC(st2205u_device::drrh_r), FUNC(st2205u_device::drrh_w));
+ map(0x0036, 0x0036).rw(FUNC(st2205u_device::brrl_r), FUNC(st2205u_device::brrl_w));
+ map(0x0037, 0x0037).rw(FUNC(st2205u_device::brrh_r), FUNC(st2205u_device::brrh_w));
+ map(0x0039, 0x0039).rw(FUNC(st2205u_device::sys_r), FUNC(st2205u_device::sys_w));
+ map(0x003a, 0x003a).rw(FUNC(st2205u_device::pmcr_r), FUNC(st2205u_device::pmcr_w));
+ map(0x003c, 0x003c).rw(FUNC(st2205u_device::ireql_r), FUNC(st2205u_device::ireql_w));
+ map(0x003d, 0x003d).rw(FUNC(st2205u_device::ireqh_r), FUNC(st2205u_device::ireqh_w));
+ map(0x003e, 0x003e).rw(FUNC(st2205u_device::ienal_r), FUNC(st2205u_device::ienal_w));
+ map(0x003f, 0x003f).rw(FUNC(st2205u_device::ienah_r), FUNC(st2205u_device::ienah_w));
+ 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(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));
+ map(0x8000, 0xffff).rw(FUNC(st2205u_device::dmem_r), FUNC(st2205u_device::dmem_w));
+}
diff --git a/src/devices/cpu/m6502/st2205u.h b/src/devices/cpu/m6502/st2205u.h
new file mode 100644
index 00000000000..15ab962b8f3
--- /dev/null
+++ b/src/devices/cpu/m6502/st2205u.h
@@ -0,0 +1,97 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Sitronix ST2205U 8-Bit Integrated Microcontroller
+
+**********************************************************************/
+
+#ifndef MAME_CPU_M6502_ST2205U_H
+#define MAME_CPU_M6502_ST2205U_H
+
+#pragma once
+
+#include "st2xxx.h"
+
+class st2205u_device : public st2xxx_device
+{
+public:
+ enum {
+ ST_BRR = ST_IENA + 1,
+ ST_LVCTR
+ };
+
+ st2205u_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ class mi_st2205u : public mi_st2xxx {
+ public:
+ virtual u8 read(u16 adr) override;
+ virtual u8 read_sync(u16 adr) override;
+ virtual u8 read_arg(u16 adr) override;
+ virtual u8 read_vector(u16 adr) override;
+ virtual void write(u16 adr, u8 val) override;
+
+ u8 pread(u16 adr);
+ u8 preadc(u16 adr);
+ void pwrite(u16 adr, u8 val);
+ u8 dread(u16 adr);
+ u8 dreadc(u16 adr);
+ void dwrite(u16 adr, u8 val);
+ u8 bread(u16 adr);
+ u8 breadc(u16 adr);
+ void bwrite(u16 adr, u8 val);
+
+ bool irr_enable;
+ u16 irr;
+ u16 prr;
+ u16 drr;
+ u16 brr;
+
+ std::unique_ptr<u8[]> ram;
+ };
+
+ 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 lvctr_r();
+ void lvctr_w(u8 data);
+
+ u8 ram_r(offs_t offset);
+ void ram_w(offs_t offset, u8 data);
+ u8 pmem_r(offs_t offset);
+ void pmem_w(offs_t offset, u8 data);
+ u8 dmem_r(offs_t offset);
+ void dmem_w(offs_t offset, u8 data);
+ u8 bmem_r(offs_t offset);
+ void bmem_w(offs_t offset, u8 data);
+
+ void int_map(address_map &map);
+
+ u8 m_lvctr;
+};
+
+DECLARE_DEVICE_TYPE(ST2205U, st2205u_device)
+
+#endif // MAME_MACHINE_M6502_ST2205_H
diff --git a/src/devices/cpu/m6502/st2xxx.cpp b/src/devices/cpu/m6502/st2xxx.cpp
new file mode 100644
index 00000000000..711360b355f
--- /dev/null
+++ b/src/devices/cpu/m6502/st2xxx.cpp
@@ -0,0 +1,252 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Sitronix ST2XXX LCD MCUs
+
+ This extended SoC family combines a 65C02 CPU core (including the
+ Rockwell bit opcodes) with a wide variety of on-chip peripherals.
+ Features common to all besides internal RAM and ROM are parallel
+ ports, internal timers, a multi-level interrupt controller, LCD
+ controllers (of varying degrees of sophistication), R/C/slow XTAL
+ clock generators, power management and PSG channels for speaker
+ output. Each MCU also has numerous pins dedicated to LCD segment
+ drivers, an external bus addressing several MB of off-chip
+ memory using multiple chip select signals, or both. Program ROM,
+ whether internal or external, is banked to a greater or lesser
+ extent except on the smallest single-chip ST20XX models.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "st2xxx.h"
+#include "r65c02d.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)
+ : 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_pdata{0}
+ , m_pctrl{0}
+ , m_psel{0}
+ , m_pfun{0}
+ , m_pmcr(0)
+ , m_ireq(0)
+ , m_iena(0)
+ , m_ireq_mask(ireq_mask)
+ , m_sys(0)
+{
+ program_config.m_internal_map = std::move(internal_map);
+}
+
+device_memory_interface::space_config_vector st2xxx_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &program_config),
+ std::make_pair(AS_DATA, &m_data_config)
+ };
+}
+
+void st2xxx_device::device_resolve_objects()
+{
+ for (auto &cb : m_in_port_cb)
+ cb.resolve_safe(0xff);
+ for (auto &cb : m_out_port_cb)
+ cb.resolve_safe();
+}
+
+void st2xxx_device::device_reset()
+{
+ m6502_device::device_reset();
+
+ // reset port registers
+ std::fill(std::begin(m_pdata), std::end(m_pdata), 0xff);
+ std::fill(std::begin(m_pctrl), std::end(m_pctrl), 0);
+ std::fill(std::begin(m_psel), std::end(m_psel), 0xff);
+ std::fill(std::begin(m_pfun), std::end(m_pfun), 0);
+ for (auto &cb : m_out_port_cb)
+ cb(0xff);
+ m_pmcr = 0x80;
+
+ // reset interrupt registers
+ m_ireq = 0;
+ m_iena = 0;
+ update_irq_state();
+
+ // reset miscellaneous registers
+ m_sys = 0;
+}
+
+std::unique_ptr<util::disasm_interface> st2xxx_device::create_disassembler()
+{
+ return std::make_unique<r65c02_disassembler>();
+}
+
+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++)
+ {
+ if (BIT(m_ireq & m_iena, level))
+ {
+ m_ireq &= ~(1 << level);
+ update_irq_state();
+ return level;
+ }
+ }
+ throw emu_fatalerror("ST2XXX: no IRQ to acknowledge!\n");
+}
+
+u8 st2xxx_device::pdata_r(offs_t offset)
+{
+ u8 pdata = m_pdata[offset];
+ u8 pinmask = ~m_pctrl[offset] | (pdata & ~m_psel[offset]);
+ if (pinmask != 0)
+ pdata = (pdata & ~pinmask) | (m_in_port_cb[offset](0, pinmask) & pinmask);
+ return pdata;
+}
+
+void st2xxx_device::pdata_w(offs_t offset, u8 data)
+{
+ if (data != m_pdata[offset])
+ {
+ m_pdata[offset] = data;
+ m_out_port_cb[offset](0, data, m_pctrl[offset]);
+ }
+}
+
+u8 st2xxx_device::pctrl_r(offs_t offset)
+{
+ return m_pctrl[offset];
+}
+
+void st2xxx_device::pctrl_w(offs_t offset, u8 data)
+{
+ if (data != m_pctrl[offset])
+ {
+ m_pctrl[offset] = data;
+ m_out_port_cb[offset](0, m_pdata[offset], data);
+ }
+}
+
+u8 st2xxx_device::pfc_r()
+{
+ return m_pfun[0];
+}
+
+void st2xxx_device::pfc_w(u8 data)
+{
+ m_pfun[0] = data;
+}
+
+u8 st2xxx_device::pfd_r()
+{
+ return m_pfun[1];
+}
+
+void st2xxx_device::pfd_w(u8 data)
+{
+ m_pfun[1] = data;
+}
+
+u8 st2xxx_device::pl_r()
+{
+ return pdata_r(6);
+}
+
+void st2xxx_device::pl_w(u8 data)
+{
+ pdata_w(6, data);
+}
+
+u8 st2xxx_device::psc_r()
+{
+ return m_psel[2];
+}
+
+void st2xxx_device::psc_w(u8 data)
+{
+ m_psel[2] = data;
+}
+
+u8 st2xxx_device::pse_r()
+{
+ return m_psel[4];
+}
+
+void st2xxx_device::pse_w(u8 data)
+{
+ m_psel[4] = data;
+}
+
+u8 st2xxx_device::pcl_r()
+{
+ return pctrl_r(6);
+}
+
+void st2xxx_device::pcl_w(u8 data)
+{
+ pctrl_w(6, data);
+}
+
+u8 st2xxx_device::ireql_r()
+{
+ return m_ireq & 0x00ff;
+}
+
+void st2xxx_device::ireql_w(u8 data)
+{
+ if ((m_ireq & ~data & 0x00ff) != 0)
+ {
+ m_ireq &= data | 0xff00;
+ update_irq_state();
+ }
+}
+
+u8 st2xxx_device::ireqh_r()
+{
+ return m_ireq >> 8;
+}
+
+void st2xxx_device::ireqh_w(u8 data)
+{
+ if ((m_ireq & ~(u16(data) << 8) & 0xff00) != 0)
+ {
+ m_ireq &= u16(data) << 8 | 0x00ff;
+ update_irq_state();
+ }
+}
+
+u8 st2xxx_device::ienal_r()
+{
+ return m_iena & 0x00ff;
+}
+
+void st2xxx_device::ienal_w(u8 data)
+{
+ m_iena = (m_iena & 0xff00) | (data & m_ireq_mask);
+ update_irq_state();
+}
+
+u8 st2xxx_device::ienah_r()
+{
+ return m_iena >> 8;
+}
+
+void st2xxx_device::ienah_w(u8 data)
+{
+ m_iena = (m_iena & 0x00ff) | ((u16(data) << 8) & m_ireq_mask);
+ update_irq_state();
+}
+
+#include "cpu/m6502/st2xxx.hxx"
diff --git a/src/devices/cpu/m6502/st2xxx.h b/src/devices/cpu/m6502/st2xxx.h
new file mode 100644
index 00000000000..2d328be54f0
--- /dev/null
+++ b/src/devices/cpu/m6502/st2xxx.h
@@ -0,0 +1,134 @@
+#ifndef MAME_CPU_M6502_ST2XXX_H
+#define MAME_CPU_M6502_ST2XXX_H
+
+#pragma once
+
+#include "r65c02.h"
+
+class st2xxx_device : public r65c02_device {
+public:
+ enum {
+ ST_PDA = M6502_IR + 1,
+ ST_PDB,
+ ST_PDC,
+ ST_PDD,
+ ST_PDE,
+ ST_PDF,
+ ST_PDL,
+ ST_PCA,
+ ST_PCB,
+ ST_PCC,
+ ST_PCD,
+ ST_PCE,
+ ST_PCF,
+ ST_PCL,
+ ST_PSA,
+ ST_PSB,
+ ST_PSC,
+ ST_PSD,
+ ST_PSE,
+ ST_PSF,
+ ST_PSL,
+ ST_PFC,
+ ST_PFD,
+ ST_PMCR,
+ ST_SYS,
+ ST_IRR,
+ ST_PRR,
+ ST_DRR,
+ ST_IREQ,
+ ST_IENA
+ };
+
+ auto in_pa_callback() { return m_in_port_cb[0].bind(); }
+ auto out_pa_callback() { return m_out_port_cb[0].bind(); }
+ auto in_pb_callback() { return m_in_port_cb[1].bind(); }
+ auto out_pb_callback() { return m_out_port_cb[1].bind(); }
+ auto in_pc_callback() { return m_in_port_cb[2].bind(); }
+ auto out_pc_callback() { return m_out_port_cb[2].bind(); }
+ auto in_pd_callback() { return m_in_port_cb[3].bind(); }
+ auto out_pd_callback() { return m_out_port_cb[3].bind(); }
+ auto in_pe_callback() { return m_in_port_cb[4].bind(); }
+ auto out_pe_callback() { return m_out_port_cb[4].bind(); }
+ auto in_pf_callback() { return m_in_port_cb[5].bind(); }
+ auto out_pf_callback() { return m_out_port_cb[5].bind(); }
+ auto in_pl_callback() { return m_in_port_cb[6].bind(); }
+ 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);
+
+ virtual space_config_vector memory_space_config() const override;
+ virtual void device_resolve_objects() override;
+ virtual void device_reset() override;
+
+ virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
+ virtual void do_exec_full() override;
+ virtual void do_exec_partial() override;
+
+ 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;
+ };
+
+ u8 read_vector(u16 adr) { return downcast<mi_st2xxx &>(*mintf).read_vector(adr); }
+ void set_irq_service(bool state) { downcast<mi_st2xxx &>(*mintf).irq_service = state; }
+
+ void update_irq_state() { irq_state = (m_ireq & m_iena) != 0; }
+ u8 acknowledge_irq();
+
+ u8 pdata_r(offs_t offset);
+ void pdata_w(offs_t offset, u8 data);
+ u8 pctrl_r(offs_t offset);
+ void pctrl_w(offs_t offset, u8 data);
+ u8 pl_r();
+ void pl_w(u8 data);
+ u8 pcl_r();
+ void pcl_w(u8 data);
+ u8 psc_r();
+ void psc_w(u8 data);
+ u8 pse_r();
+ void pse_w(u8 data);
+ u8 pfc_r();
+ void pfc_w(u8 data);
+ u8 pfd_r();
+ void pfd_w(u8 data);
+
+ u8 ireql_r();
+ void ireql_w(u8 data);
+ u8 ireqh_r();
+ void ireqh_w(u8 data);
+ u8 ienal_r();
+ void ienal_w(u8 data);
+ u8 ienah_r();
+ void ienah_w(u8 data);
+
+#define O(o) void o ## _full(); void o ## _partial()
+
+ O(brk_st_imp);
+ O(rti_st_imp);
+ O(reset_st);
+
+#undef O
+
+ address_space_config m_data_config;
+
+ devcb_read8 m_in_port_cb[7];
+ devcb_write8 m_out_port_cb[7];
+
+ u8 m_pdata[7];
+ u8 m_pctrl[7];
+ u8 m_psel[7];
+ u8 m_pfun[2];
+ u8 m_pmcr;
+ u16 m_ireq;
+ u16 m_iena;
+ const u16 m_ireq_mask;
+ u8 m_sys;
+};
+
+#endif // MAME_CPU_M6502_ST2XXX_H