summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/m6502/st2204.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/m6502/st2204.cpp')
-rw-r--r--src/devices/cpu/m6502/st2204.cpp119
1 files changed, 91 insertions, 28 deletions
diff --git a/src/devices/cpu/m6502/st2204.cpp b/src/devices/cpu/m6502/st2204.cpp
index b56d4482336..55c837fb8d6 100644
--- a/src/devices/cpu/m6502/st2204.cpp
+++ b/src/devices/cpu/m6502/st2204.cpp
@@ -45,7 +45,7 @@ st2204_device::st2204_device(const machine_config &mconfig, device_type type, co
, m_tmode{0}
, m_tcntr{0}
, m_tload{0}
- , m_t0_timer(nullptr)
+ , m_timer{0}
, m_psg{0}
, m_psgc(0)
, m_dms(0)
@@ -78,7 +78,8 @@ void st2204_device::device_start()
init_base_timer(0x0020);
- m_t0_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2204_device::t0_interrupt), this));
+ m_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2204_device::t0_interrupt), this));
+ m_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2204_device::t1_interrupt), this));
save_item(NAME(m_tmode));
save_item(NAME(m_tcntr));
@@ -100,14 +101,14 @@ void st2204_device::device_start()
state_add<u16>(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]);
+ state_add(ST_PAOUT + i, string_format("P%cOUT", '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_PLOUT, "PLOUT", m_pdata[6]);
state_add(ST_PCL, "PCL", m_pctrl[6]);
state_add(ST_PMCR, "PMCR", m_pmcr);
state_add<u8>(ST_PRS, "PRS", [this]() { return m_prs; }, [this](u8 data) { prs_w(data); }).mask(0x60);
@@ -132,6 +133,9 @@ void st2204_device::device_start()
state_add(ST_LFRA, "LFRA", m_lfra).mask(0x3f);
state_add(ST_LAC, "LAC", m_lac).mask(0x1f);
state_add(ST_LPWM, "LPWM", m_lpwm).mask(st2xxx_lpwm_mask());
+ state_add(ST_BCTR, "BCTR", m_bctr).mask(0x87);
+ state_add(ST_BRS, "BRS", m_brs);
+ state_add(ST_BDIV, "BDIV", m_bdiv);
state_add(ST_DMS, "DMS", m_dms);
state_add(ST_DMR, "DMR", downcast<mi_st2204 &>(*mintf).dmr).mask(0x7ff);
state_add(ST_DMD, "DMD", m_dmd);
@@ -144,7 +148,8 @@ void st2204_device::device_reset()
m_tmode[0] = m_tmode[1] = 0;
m_tcntr[0] = m_tcntr[1] = 0;
m_tload[0] = m_tload[1] = 0;
- m_t0_timer->adjust(attotime::never);
+ m_timer[0]->adjust(attotime::never);
+ m_timer[1]->adjust(attotime::never);
m_psg[0] = m_psg[1] = 0;
m_psgc = 0;
@@ -235,16 +240,6 @@ 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;
-}
-
unsigned st2204_device::st2xxx_bt_divider(int n) const
{
// 2 Hz, 8 Hz, 64 Hz, 256 Hz, 2048 Hz
@@ -261,13 +256,32 @@ TIMER_CALLBACK_MEMBER(st2204_device::t0_interrupt)
// Bit 4 allows auto-reload
m_tcntr[0] = BIT(m_tmode[0], 4) ? m_tload[0] : 0;
- m_t0_timer->adjust(cycles_to_attotime((256 - m_tcntr[0]) * tclk_pres_div(m_tmode[0] & 0x07)));
+ m_timer[0]->adjust(cycles_to_attotime((256 - m_tcntr[0]) * tclk_pres_div(m_tmode[0] & 0x07)));
+}
+
+TIMER_CALLBACK_MEMBER(st2204_device::t1_interrupt)
+{
+ m_ireq |= 0x008;
+ update_irq_state();
+
+ // Bit 4 allows auto-reload
+ m_tcntr[1] = BIT(m_tmode[1], 4) ? m_tload[1] : 0;
+ if (!BIT(m_tmode[1], 3))
+ m_timer[1]->adjust(cycles_to_attotime((256 - m_tcntr[1]) * tclk_pres_div(m_tmode[1] & 0x07)));
+ else if ((m_tmode[1] & 0x07) < 3)
+ t1_start_from_oscx();
}
-void st2204_device::t0_start()
+void st2204_device::timer_start_from_tclk(int t)
{
- u32 div = tclk_pres_div(m_tmode[0] & 0x07);
- m_t0_timer->adjust(cycles_to_attotime((255 - m_tcntr[0]) * div + div - (pres_count() & (div - 1))));
+ u32 div = tclk_pres_div(m_tmode[t] & 0x07);
+ m_timer[t]->adjust(cycles_to_attotime((255 - m_tcntr[t]) * div + div - (pres_count() & (div - 1))));
+}
+
+void st2204_device::t1_start_from_oscx()
+{
+ u32 div = 256 >> (m_tmode[1] & 0x03);
+ m_timer[1]->adjust(attotime::from_ticks(div, 32768));
}
u8 st2204_device::t0m_r()
@@ -285,9 +299,9 @@ void st2204_device::t0m_w(u8 data)
m_tcntr[0] = t0c_r();
if (BIT(data, 5))
- t0_start();
+ timer_start_from_tclk(0);
else if (BIT(t0m_old, 5))
- m_t0_timer->adjust(attotime::never);
+ m_timer[0]->adjust(attotime::never);
}
}
@@ -298,7 +312,7 @@ u8 st2204_device::t0c_r()
else
{
u32 div = tclk_pres_div(m_tmode[0] & 0x07);
- return 255 - u8(attotime_to_cycles(m_t0_timer->remaining()) / div);
+ return 255 - u8(attotime_to_cycles(m_timer[0]->remaining()) / div);
}
}
@@ -306,7 +320,7 @@ void st2204_device::t0c_w(u8 data)
{
m_tcntr[0] = m_tload[0] = data;
if ((m_prs & 0x60) == 0x40 && BIT(m_tmode[0], 5))
- t0_start();
+ timer_start_from_tclk(0);
}
u8 st2204_device::t1m_r()
@@ -316,12 +330,48 @@ u8 st2204_device::t1m_r()
void st2204_device::t1m_w(u8 data)
{
- m_tmode[1] = data & 0x1f;
+ data &= 0x1f;
+ u8 t1m_old = std::exchange(m_tmode[1], data);
+
+ if ((data & 0x0f) != (t1m_old & 0x0f))
+ {
+ // forced update
+ m_tcntr[1] = t1c_r();
+
+ if (!BIT(data, 3))
+ {
+ if ((m_prs & 0x60) == 0x40)
+ timer_start_from_tclk(1);
+ else
+ m_timer[1]->adjust(attotime::never);
+ }
+ else if (data < 0x0b)
+ t1_start_from_oscx();
+
+ // TODO: BGRCK source
+ }
+
}
u8 st2204_device::t1c_r()
{
- return m_tcntr[1];
+ if (!BIT(m_tmode[1], 3))
+ {
+ if ((m_prs & 0x60) != 0x40)
+ return m_tcntr[1];
+ else
+ {
+ u32 div = tclk_pres_div(m_tmode[1] & 0x07);
+ return 255 - u8(attotime_to_cycles(m_timer[1]->remaining()) / div);
+ }
+ }
+ else if ((m_tmode[1] & 0x07) < 3)
+ {
+ u32 div = 256 >> (m_tmode[1] & 0x03);
+ return 255 - u8(m_timer[1]->remaining().as_ticks(32768) / div);
+ }
+ else
+ return m_tcntr[1];
}
void st2204_device::t1c_w(u8 data)
@@ -332,13 +382,23 @@ void st2204_device::t1c_w(u8 data)
void st2204_device::st2xxx_tclk_start()
{
if (BIT(m_tmode[0], 5))
- t0_start();
+ timer_start_from_tclk(0);
+ if (!BIT(m_tmode[1], 3))
+ timer_start_from_tclk(1);
}
void st2204_device::st2xxx_tclk_stop()
{
- m_tcntr[0] = t0c_r();
- m_t0_timer->adjust(attotime::never);
+ if (m_timer[0]->enabled())
+ {
+ m_tcntr[0] = t0c_r();
+ m_timer[0]->adjust(attotime::never);
+ }
+ if (!BIT(m_tmode[1], 3))
+ {
+ m_tcntr[1] = t1c_r();
+ m_timer[1]->adjust(attotime::never);
+ }
}
void st2204_device::psg_w(offs_t offset, u8 data)
@@ -500,6 +560,9 @@ void st2204_device::common_map(address_map &map)
map(0x004c, 0x004c).rw(FUNC(st2204_device::pl_r), FUNC(st2204_device::pl_w));
// PCL is listed as write-only in ST2202 specification, but DynamiDesk suggests otherwise
map(0x004e, 0x004e).rw(FUNC(st2204_device::pcl_r), FUNC(st2204_device::pcl_w));
+ map(0x0063, 0x0063).rw(FUNC(st2204_device::bctr_r), FUNC(st2204_device::bctr_w));
+ map(0x0066, 0x0066).rw(FUNC(st2204_device::brs_r), FUNC(st2204_device::brs_w));
+ map(0x0067, 0x0067).rw(FUNC(st2204_device::bdiv_r), FUNC(st2204_device::bdiv_w));
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));
}