summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2019-11-08 09:33:43 -0500
committer AJR <ajrhacker@users.noreply.github.com>2019-11-08 09:34:50 -0500
commit576e9ee12e2399312d78b629975018711cf6fd97 (patch)
tree48fc55cf566b55cc3b9b38bc659c35c2c1693241 /src/devices/cpu
parent8801bb8f8d22f8b48a2df68a8616d4af300bb514 (diff)
st2xxx: Calculate LCD frame rate and emulate related interrupt (nw)
st2204: Fix logic mistake in psg_w (nw)
Diffstat (limited to 'src/devices/cpu')
-rw-r--r--src/devices/cpu/m6502/st2204.cpp14
-rw-r--r--src/devices/cpu/m6502/st2204.h1
-rw-r--r--src/devices/cpu/m6502/st2205u.cpp11
-rw-r--r--src/devices/cpu/m6502/st2205u.h1
-rw-r--r--src/devices/cpu/m6502/st2xxx.cpp44
-rw-r--r--src/devices/cpu/m6502/st2xxx.h7
6 files changed, 75 insertions, 3 deletions
diff --git a/src/devices/cpu/m6502/st2204.cpp b/src/devices/cpu/m6502/st2204.cpp
index 55c837fb8d6..829ff74ac08 100644
--- a/src/devices/cpu/m6502/st2204.cpp
+++ b/src/devices/cpu/m6502/st2204.cpp
@@ -77,6 +77,7 @@ void st2204_device::device_start()
intf->irq_service = false;
init_base_timer(0x0020);
+ init_lcd_timer(0x0040);
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));
@@ -404,7 +405,7 @@ void st2204_device::st2xxx_tclk_stop()
void st2204_device::psg_w(offs_t offset, u8 data)
{
if (BIT(offset, 0))
- m_psg[offset >> 1] = u16(data << 8) | (m_psg[offset >> 1] & 0x0ff);
+ m_psg[offset >> 1] = u16(data & 0x0f) << 8 | (m_psg[offset >> 1] & 0x0ff);
else
m_psg[offset >> 1] = data | (m_psg[offset >> 1] & 0xf00);
}
@@ -419,6 +420,17 @@ void st2204_device::dac_w(u8 data)
// TODO
}
+unsigned st2204_device::st2xxx_lfr_clocks() const
+{
+ // ST2202 datasheet suggests 1/4 as many clocks in 4-bit mode; this seems too fast for GameKing 3 (TODO: double-check this)
+ unsigned lcdcks = ((m_lxmax + m_lfra) * 2 + 3) * 8 * (m_lymax ? m_lymax : 256);
+
+ if (BIT(m_lckr, 4))
+ return lcdcks * std::max((m_lckr & 0x0f) * 2, 1);
+ else
+ return lcdcks * std::max(((m_lckr & 0x0c) >> 2) * 2, 1);
+}
+
u8 st2204_device::dmsl_r()
{
return m_dms & 0xff;
diff --git a/src/devices/cpu/m6502/st2204.h b/src/devices/cpu/m6502/st2204.h
index 8cca3c57085..6c5772b7ecf 100644
--- a/src/devices/cpu/m6502/st2204.h
+++ b/src/devices/cpu/m6502/st2204.h
@@ -50,6 +50,7 @@ protected:
virtual u8 st2xxx_lctr_mask() const override { return 0xff; }
virtual u8 st2xxx_lckr_mask() const override { return 0x1f; }
virtual u8 st2xxx_lpwm_mask() const override { return 0x3f; }
+ virtual unsigned st2xxx_lfr_clocks() const override;
virtual u8 st2xxx_bctr_mask() const override { return 0x87; }
void common_map(address_map &map);
diff --git a/src/devices/cpu/m6502/st2205u.cpp b/src/devices/cpu/m6502/st2205u.cpp
index 100169584a9..c6036fbe21d 100644
--- a/src/devices/cpu/m6502/st2205u.cpp
+++ b/src/devices/cpu/m6502/st2205u.cpp
@@ -62,6 +62,7 @@ void st2205u_device::device_start()
intf->ram = make_unique_clear<u8[]>(0x8000);
init_base_timer(0x0040);
+ init_lcd_timer(0x0080);
save_item(NAME(m_btc));
save_item(NAME(m_tc_12bit));
@@ -349,6 +350,16 @@ void st2205u_device::st2xxx_tclk_stop()
{
}
+unsigned st2205u_device::st2xxx_lfr_clocks() const
+{
+ unsigned lcdcks = ((m_lxmax * 2 + m_lfra * 4) + 5) * (m_lymax ? m_lymax : 256) * ((m_lctr & 0x03) == 0 ? 2 : 4);
+
+ if ((m_lckr & 0x30) == 0x00 || (m_lckr & 0x30) == 0x30)
+ return lcdcks * std::max(((m_lckr & 0x0c) >> 2) * 8, 4);
+ else
+ return lcdcks * std::max((m_lckr & 0x0f) * 2, 1);
+}
+
u8 st2205u_device::lvctr_r()
{
return m_lvctr | 0x01;
diff --git a/src/devices/cpu/m6502/st2205u.h b/src/devices/cpu/m6502/st2205u.h
index edde62aea71..f8ee13649d1 100644
--- a/src/devices/cpu/m6502/st2205u.h
+++ b/src/devices/cpu/m6502/st2205u.h
@@ -49,6 +49,7 @@ protected:
virtual u8 st2xxx_lctr_mask() const override { return 0xef; }
virtual u8 st2xxx_lckr_mask() const override { return 0x3f; }
virtual u8 st2xxx_lpwm_mask() const override { return 0xff; }
+ virtual unsigned st2xxx_lfr_clocks() const override;
virtual u8 st2xxx_bctr_mask() const override { return 0xb7; }
private:
diff --git a/src/devices/cpu/m6502/st2xxx.cpp b/src/devices/cpu/m6502/st2xxx.cpp
index 62fd8871f85..47d6b6778b4 100644
--- a/src/devices/cpu/m6502/st2xxx.cpp
+++ b/src/devices/cpu/m6502/st2xxx.cpp
@@ -30,7 +30,8 @@
#define LOG_IRQ (1 << 1U)
#define LOG_BT (1 << 2U)
-//#define VERBOSE (LOG_IRQ | LOG_BT)
+#define LOG_LCDC (1 << 3U)
+//#define VERBOSE (LOG_IRQ | LOG_BT | LOG_LCDC)
#include "logmacro.h"
st2xxx_device::st2xxx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor internal_map, int data_bits, bool has_banked_ram)
@@ -66,6 +67,8 @@ st2xxx_device::st2xxx_device(const machine_config &mconfig, device_type type, co
, m_lfra(0)
, m_lac(0)
, m_lpwm(0)
+ , m_lcd_ireq(0)
+ , m_lcd_timer(nullptr)
, m_bctr(0)
{
program_config.m_internal_map = std::move(internal_map);
@@ -123,6 +126,20 @@ void st2xxx_device::init_base_timer(u16 ireq)
assert(m_bt_ireq != 0);
}
+TIMER_CALLBACK_MEMBER(st2xxx_device::lcd_interrupt)
+{
+ m_ireq |= m_lcd_ireq;
+ update_irq_state();
+}
+
+void st2xxx_device::init_lcd_timer(u16 ireq)
+{
+ m_lcd_ireq = ireq;
+ assert(m_lcd_ireq != 0);
+
+ m_lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(st2xxx_device::lcd_interrupt), this));
+}
+
void st2xxx_device::save_common_registers()
{
mi_st2xxx *intf = downcast<mi_st2xxx *>(mintf.get());
@@ -228,6 +245,7 @@ void st2xxx_device::device_reset()
m_lfra = 0;
m_lac = 0;
m_lpwm = 0;
+ m_lcd_timer->adjust(attotime::never);
// reset UART and BRG
m_bctr = 0;
@@ -676,6 +694,7 @@ u8 st2xxx_device::lxmax_r()
void st2xxx_device::lxmax_w(u8 data)
{
m_lxmax = data;
+ lfr_recalculate_period();
}
u8 st2xxx_device::lymax_r()
@@ -686,6 +705,7 @@ u8 st2xxx_device::lymax_r()
void st2xxx_device::lymax_w(u8 data)
{
m_lymax = data;
+ lfr_recalculate_period();
}
u8 st2xxx_device::lpan_r()
@@ -705,17 +725,37 @@ u8 st2xxx_device::lctr_r()
void st2xxx_device::lctr_w(u8 data)
{
- m_lctr = data & st2xxx_lctr_mask();
+ data &= st2xxx_lctr_mask();
+ u8 old_lctr = std::exchange(m_lctr, data);
+
+ if ((old_lctr & 0xbf) != (m_lctr & 0xbf))
+ lfr_recalculate_period();
}
void st2xxx_device::lckr_w(u8 data)
{
m_lckr = data & st2xxx_lckr_mask();
+ lfr_recalculate_period();
}
void st2xxx_device::lfra_w(u8 data)
{
m_lfra = data & 0x3f;
+ lfr_recalculate_period();
+}
+
+void st2xxx_device::lfr_recalculate_period()
+{
+ if (!BIT(m_lctr, 7))
+ {
+ unsigned clocks = st2xxx_lfr_clocks();
+ assert(clocks != 0);
+ attotime period = cycles_to_attotime(clocks);
+ LOGMASKED(LOG_LCDC, "LCD frame rate = %f Hz (PC = $%04X)\n", period.as_hz(), PPC);
+ m_lcd_timer->adjust(period, 0, period);
+ }
+ else
+ m_lcd_timer->adjust(attotime::never);
}
u8 st2xxx_device::lac_r()
diff --git a/src/devices/cpu/m6502/st2xxx.h b/src/devices/cpu/m6502/st2xxx.h
index e72e5c36d95..9dbdef3ba24 100644
--- a/src/devices/cpu/m6502/st2xxx.h
+++ b/src/devices/cpu/m6502/st2xxx.h
@@ -99,6 +99,7 @@ protected:
virtual u8 st2xxx_lctr_mask() const = 0;
virtual u8 st2xxx_lckr_mask() const = 0;
virtual u8 st2xxx_lpwm_mask() const = 0;
+ virtual unsigned st2xxx_lfr_clocks() const = 0;
virtual u8 st2xxx_bctr_mask() const = 0;
class mi_st2xxx : public memory_interface {
@@ -117,6 +118,7 @@ protected:
};
void init_base_timer(u16 ireq);
+ void init_lcd_timer(u16 ireq);
void save_common_registers();
u8 read_vector(u16 adr) { return downcast<mi_st2xxx &>(*mintf).read_vector(adr); }
@@ -126,6 +128,7 @@ protected:
u8 acknowledge_irq();
TIMER_CALLBACK_MEMBER(bt_interrupt);
+ TIMER_CALLBACK_MEMBER(lcd_interrupt);
u8 pdata_r(offs_t offset);
void pdata_w(offs_t offset, u8 data);
@@ -201,6 +204,7 @@ protected:
void lctr_w(u8 data);
void lckr_w(u8 data);
void lfra_w(u8 data);
+ void lfr_recalculate_period();
u8 lac_r();
void lac_w(u8 data);
u8 lpwm_r();
@@ -260,6 +264,9 @@ protected:
u8 m_lfra;
u8 m_lac;
u8 m_lpwm;
+ u16 m_lcd_ireq;
+ emu_timer *m_lcd_timer;
+
u8 m_bctr;
u8 m_brs;
u8 m_bdiv;