Preliminary SoC emulation for Sitronix ST2204 and ST2205U

This commit is contained in:
AJR 2019-11-03 11:30:14 -05:00
parent 7791be49e4
commit 27ddae4ecf
10 changed files with 1344 additions and 88 deletions

View File

@ -1434,6 +1434,9 @@ end
--@src/devices/cpu/m6502/m740.h,CPUS["M6502"] = true
--@src/devices/cpu/m6502/m3745x.h,CPUS["M6502"] = true
--@src/devices/cpu/m6502/m5074x.h,CPUS["M6502"] = true
--@src/devices/cpu/m6502/st2xxx.h,CPUS["M6502"] = true
--@src/devices/cpu/m6502/st2204.h,CPUS["M6502"] = true
--@src/devices/cpu/m6502/st2205u.h,CPUS["M6502"] = true
--@src/devices/cpu/m6502/xavix.h,CPUS["XAVIX"] = true
--@src/devices/cpu/m6502/xavix.h,CPUS["XAVIX2000"] = true
@ -1479,6 +1482,12 @@ if (CPUS["M6502"]~=null) then
MAME_DIR .. "src/devices/cpu/m6502/m3745x.h",
MAME_DIR .. "src/devices/cpu/m6502/m5074x.cpp",
MAME_DIR .. "src/devices/cpu/m6502/m5074x.h",
MAME_DIR .. "src/devices/cpu/m6502/st2xxx.cpp",
MAME_DIR .. "src/devices/cpu/m6502/st2xxx.h",
MAME_DIR .. "src/devices/cpu/m6502/st2204.cpp",
MAME_DIR .. "src/devices/cpu/m6502/st2204.h",
MAME_DIR .. "src/devices/cpu/m6502/st2205u.cpp",
MAME_DIR .. "src/devices/cpu/m6502/st2205u.h",
MAME_DIR .. "src/devices/cpu/m6502/xavix.cpp",
MAME_DIR .. "src/devices/cpu/m6502/xavix.h",
MAME_DIR .. "src/devices/cpu/m6502/xavix2000.cpp",
@ -1496,6 +1505,7 @@ if (CPUS["M6502"]~=null) then
{ MAME_DIR .. "src/devices/cpu/m6502/on2a03.lst", GEN_DIR .. "emu/cpu/m6502/n2a03.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", MAME_DIR .. "src/devices/cpu/m6502/dn2a03.lst" }, {"@echo Generating n2a03 disassembler source file...", PYTHON .. " $(1) s n2a03 $(<) $(2) $(@)" }},
{ MAME_DIR .. "src/devices/cpu/m6502/om740.lst" , GEN_DIR .. "emu/cpu/m6502/m740.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", MAME_DIR .. "src/devices/cpu/m6502/dm740.lst" }, {"@echo Generating m740 disassembler source file...", PYTHON .. " $(1) s m740 $(<) $(2) $(@)" }},
{ MAME_DIR .. "src/devices/cpu/m6502/dr65c02.lst", GEN_DIR .. "emu/cpu/m6502/r65c02.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", }, {"@echo Generating r65c02 disassembler source file...", PYTHON .. " $(1) s r65c02 - $(<) $(@)" }},
{ MAME_DIR .. "src/devices/cpu/m6502/ost2xxx.lst" , GEN_DIR .. "emu/cpu/m6502/st2xxx.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", MAME_DIR .. "src/devices/cpu/m6502/dst2xxx.lst" }, {"@echo Generating st2xxx disassembler source file...", PYTHON .. " $(1) s st2xxx $(<) $(2) $(@)" }},
{ MAME_DIR .. "src/devices/cpu/m6502/oxavix.lst", GEN_DIR .. "emu/cpu/m6502/xavix.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", MAME_DIR .. "src/devices/cpu/m6502/dxavix.lst" }, {"@echo Generating xavix disassembler source file...", PYTHON .. " $(1) s xavix $(<) $(2) $(@)" }},
{ MAME_DIR .. "src/devices/cpu/m6502/oxavix2000.lst", GEN_DIR .. "emu/cpu/m6502/xavix2000.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", MAME_DIR .. "src/devices/cpu/m6502/dxavix2000.lst" }, {"@echo Generating xavix2000 disassembler source file...", PYTHON .. " $(1) s xavix2000 $(<) $(2) $(@)" }},
}
@ -1511,6 +1521,7 @@ if (CPUS["M6502"]~=null) then
{ MAME_DIR .. "src/devices/cpu/m6502/n2a03.cpp", GEN_DIR .. "emu/cpu/m6502/n2a03.hxx" },
{ MAME_DIR .. "src/devices/cpu/m6502/r65c02.cpp", GEN_DIR .. "emu/cpu/m6502/r65c02.hxx" },
{ MAME_DIR .. "src/devices/cpu/m6502/m740.cpp", GEN_DIR .. "emu/cpu/m6502/m740.hxx" },
{ MAME_DIR .. "src/devices/cpu/m6502/st2xxx.cpp", GEN_DIR .. "emu/cpu/m6502/st2xxx.hxx" },
{ MAME_DIR .. "src/devices/cpu/m6502/xavix.cpp", GEN_DIR .. "emu/cpu/m6502/xavix.hxx" },
{ MAME_DIR .. "src/devices/cpu/m6502/xavix2000.cpp", GEN_DIR .. "emu/cpu/m6502/xavix2000.hxx" },
}

View File

@ -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

View File

@ -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;

View File

@ -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));
}

View File

@ -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

View File

@ -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));
}

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -1,125 +1,61 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
// copyright-holders:AJR
/***************************************************************************
inteladv.cpp: VTech Intelligence Advance E/R Lerncomputer
CPU is a Rockwell R65C02 (the dead-end bit-twiddling 65C02, as opposed to
the WDC version that the 65816 is back-compatible with) with some customizations:
JMP (ZP) accepts a 3rd ZP location after the 16-bit address to jump to which
contains a bank value for the ROM window at 0x4000. I believe it's in 0x4000
byte segments, as the first long jump uses a value of 4 and that leads to
the correct start of a subroutine at 0x10000 + the offset.
JSR / RTS may also push and pop an additional byte for the bank offset but
this is not proven yet.
VTech Intelligence Advance E/R Lerncomputer
***************************************************************************/
#include "emu.h"
#include "cpu/m6502/r65c02.h"
#include "machine/timer.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
#include "cpu/m6502/st2204.h"
#include "cpu/m6502/st2205u.h"
class inteladv_state : public driver_device
{
public:
inteladv_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_palette(*this, "palette")
{ }
inteladv_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
{
}
void inteladv(machine_config &config);
void dyndesk(machine_config &config);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
private:
u32 screen_update_inteladv(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void inteladv_main(address_map &map);
void dyndesk_main(address_map &map);
void inteladv_map(address_map &map);
void dyndesk_map(address_map &map);
required_device<cpu_device> m_maincpu;
required_device<palette_device> m_palette;
};
void inteladv_state::video_start()
void inteladv_state::inteladv_map(address_map &map)
{
map(0x000000, 0x7fffff).rom().region("maincpu", 0);
}
u32 inteladv_state::screen_update_inteladv(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
void inteladv_state::dyndesk_map(address_map &map)
{
bitmap.fill(0, cliprect);
screen.priority().fill(0, cliprect);
return 0;
}
void inteladv_state::inteladv_main(address_map &map)
{
map(0x0000, 0x01ff).ram(); // zero page and stack
map(0x4000, 0x5fff).rom().region("maincpu", 0x0000); // boot code at 4000
map(0x8000, 0x8fff).rom().region("maincpu", 0x8000); // fixed ROM region?
map(0xf000, 0xffff).rom().region("maincpu", 0x3000); // boot and other vectors at 3FFx
}
void inteladv_state::dyndesk_main(address_map &map)
{
map(0x0000, 0x0fff).ram();
map(0x4000, 0x5fff).rom().region("maincpu", 0x4000); // FIXME: this is banked
map(0xc000, 0xdfff).rom().region("maincpu", 0x4000);
map(0xffe0, 0xffff).rom().region("maincpu", 0x7fe0); // vectors are good for boot, but may also be banked
map(0x000000, 0x1fffff).rom().region("maincpu", 0).nopw(); // writes to low memory go to external RAM instead?
}
static INPUT_PORTS_START( inteladv )
INPUT_PORTS_END
void inteladv_state::machine_start()
{
}
void inteladv_state::machine_reset()
{
}
void inteladv_state::inteladv(machine_config &config)
{
/* basic machine hardware */
R65C02(config, m_maincpu, XTAL(1'000'000));
m_maincpu->set_addrmap(AS_PROGRAM, &inteladv_state::inteladv_main);
/* video hardware */
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(59.62); /* verified on pcb */
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
screen.set_size(64*8, 32*8);
screen.set_visarea(40, 400-1, 16, 240-1);
screen.set_screen_update(FUNC(inteladv_state::screen_update_inteladv));
screen.set_palette("palette");
PALETTE(config, "palette").set_format(palette_device::xBGR_888, 256).enable_shadows();
/* sound hardware */
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
ST2205U(config, m_maincpu, 32768 * 122);
m_maincpu->set_addrmap(AS_DATA, &inteladv_state::inteladv_map);
}
void inteladv_state::dyndesk(machine_config &config)
{
inteladv(config);
m_maincpu->set_addrmap(AS_PROGRAM, &inteladv_state::dyndesk_main);
ST2204(config, m_maincpu, 32768 * 122);
m_maincpu->set_addrmap(AS_DATA, &inteladv_state::dyndesk_map);
}
ROM_START( inteladv )
ROM_REGION( 0x800000, "maincpu", 0 ) /* main program */
ROM_REGION( 0x800000, "maincpu", 0 )
ROM_LOAD( "vtechinteladv.bin", 0x000000, 0x800000, CRC(e24dbbcb) SHA1(7cb7f25f5eb123ae4c46cd4529aafd95508b2210) )
ROM_END
@ -135,7 +71,7 @@ ROM_START( cars2lap )
ROM_LOAD("n25s16.u6", 0x00000, 0x200000, CRC(ec1ba96e) SHA1(51b8844ae77adf20f74f268d380d268c9ce19785))
ROM_END
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
COMP( 2005, inteladv, 0, 0, inteladv, inteladv, inteladv_state, empty_init, "VTech", "Intelligence Advance E/R (Germany)", MACHINE_NOT_WORKING )
COMP( 2003, dyndesk, 0, 0, dyndesk, inteladv, inteladv_state, empty_init, "VTech", "DynamiDesk (Germany)", MACHINE_NOT_WORKING )
COMP( 2012, cars2lap, 0, 0, inteladv, inteladv, inteladv_state, empty_init, "VTech", "CARS 2 Laptop (Germany)", MACHINE_IS_SKELETON ) // might not belong here
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
COMP( 2005, inteladv, 0, 0, inteladv, inteladv, inteladv_state, empty_init, "VTech", "Intelligence Advance E/R (Germany)", MACHINE_IS_SKELETON )
COMP( 2003, dyndesk, 0, 0, dyndesk, inteladv, inteladv_state, empty_init, "VTech", "DynamiDesk (Germany)", MACHINE_IS_SKELETON )
COMP( 2012, cars2lap, 0, 0, dyndesk, inteladv, inteladv_state, empty_init, "VTech", "CARS 2 Laptop (Germany)", MACHINE_IS_SKELETON ) // probably doesn't belong here