summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author MooglyGuy <MooglyGuy@users.noreply.github.com>2022-12-21 17:15:56 +0100
committer GitHub <noreply@github.com>2022-12-22 03:15:56 +1100
commit31784420490007231546cfa07150d069fb339f34 (patch)
treecff373451a7e790ff7ebb318e1716e1dfa1453b3
parent14c680e940fa6e713360a44b9d6718449f35aa7b (diff)
More MC68EZ328 work for palmm100 and iqunlim (#10696) [Ryan Holtz]
* palm/palm.cpp: Promoted palmm100 to working. Split Palm LCD into a separate device. * machine/mc68328.cpp: Improved LCD controller emulation. Fixed reported Coverity issues * vidoe/mc68328lcd.cpp: Added a generic device to handle MC68328-style LCD output signals. * vtech/iqunlim.cpp: Hooked up MC68EZ328 device. Clones promoted to working --------------------- 3Com Palm m100 [Ryan Holtz]
-rw-r--r--scripts/src/video.lua12
-rw-r--r--src/devices/machine/mc68328.cpp114
-rw-r--r--src/devices/machine/mc68328.h34
-rw-r--r--src/devices/video/mc68328lcd.cpp149
-rw-r--r--src/devices/video/mc68328lcd.h53
-rw-r--r--src/mame/palm/palm.cpp382
-rw-r--r--src/mame/vtech/iqunlim.cpp125
7 files changed, 634 insertions, 235 deletions
diff --git a/scripts/src/video.lua b/scripts/src/video.lua
index 23e502444af..91d65a7eff4 100644
--- a/scripts/src/video.lua
+++ b/scripts/src/video.lua
@@ -691,6 +691,18 @@ end
--------------------------------------------------
--
+--@src/devices/video/mc68328lcd.h,VIDEOS["MC68328LCD"] = true
+--------------------------------------------------
+
+if (VIDEOS["MC68328LCD"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/video/mc68328lcd.cpp",
+ MAME_DIR .. "src/devices/video/mc68328lcd.h",
+ }
+end
+
+--------------------------------------------------
+--
--@src/devices/video/mc6845.h,VIDEOS["MC6845"] = true
--------------------------------------------------
diff --git a/src/devices/machine/mc68328.cpp b/src/devices/machine/mc68328.cpp
index 8f43307bcd8..004dab62a89 100644
--- a/src/devices/machine/mc68328.cpp
+++ b/src/devices/machine/mc68328.cpp
@@ -373,7 +373,7 @@ void mc68328_base_device::device_start()
m_spim = timer_alloc(FUNC(mc68328_base_device::spim_tick), this);
m_lcd_scan = timer_alloc(FUNC(mc68328_base_device::lcd_scan_tick), this);
- m_lcd_line_buffer = std::make_unique<u16[]>(1024 / 8); // 1024px wide, up to 8 pixels per word
+ m_lcd_line_buffer = std::make_unique<u16[]>(1024 / 16); // 1024px wide, up to 16 pixels per word
register_state_save();
}
@@ -466,6 +466,7 @@ void mc68328_base_device::device_reset()
m_umisc = 0x0000;
m_lssa = 0x00000000;
+ m_lssa_end = 0x00000000;
m_lvpw = 0xff;
m_lxmax = 0x03ff;
m_lymax = 0x01ff;
@@ -480,6 +481,7 @@ void mc68328_base_device::device_reset()
m_lckcon = 0x40;
m_lposr = 0x00;
m_lfrcm = 0xb9;
+ m_lcd_update_pending = true;
m_hmsr = 0x00000000;
m_alarm = 0x00000000;
@@ -496,6 +498,7 @@ void mc68328_base_device::device_reset()
m_spim->adjust(attotime::never);
m_lcd_scan->adjust(attotime::never);
m_lcd_sysmem_ptr = 0;
+ m_lssa_end = 0;
m_lcd_line_bit = 0;
m_lcd_line_word = 0;
m_lsclk = false;
@@ -647,6 +650,7 @@ void mc68328_base_device::register_state_save()
save_item(NAME(m_umisc));
save_item(NAME(m_lssa));
+ save_item(NAME(m_lssa_end));
save_item(NAME(m_lvpw));
save_item(NAME(m_lxmax));
save_item(NAME(m_lymax));
@@ -659,11 +663,9 @@ void mc68328_base_device::register_state_save()
save_item(NAME(m_lacdrc));
save_item(NAME(m_lpxcd));
save_item(NAME(m_lckcon));
- save_item(NAME(m_llbar));
- save_item(NAME(m_lotcr));
save_item(NAME(m_lposr));
save_item(NAME(m_lfrcm));
- save_item(NAME(m_lgpmr));
+ save_item(NAME(m_lcd_update_pending));
save_item(NAME(m_hmsr));
save_item(NAME(m_alarm));
@@ -723,6 +725,10 @@ void mc68328_device::register_state_save()
save_item(NAME(m_wcn));
save_item(NAME(m_spisr));
+
+ save_item(NAME(m_llbar));
+ save_item(NAME(m_lotcr));
+ save_item(NAME(m_lgpmr));
}
void mc68ez328_device::register_state_save()
@@ -1374,31 +1380,31 @@ void mc68328_base_device::isr_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x
{
LOGMASKED(LOG_INTS, "%s: isr_msw_w: ISR(MSW) = %04x\n", machine().describe_context(), data);
// Clear edge-triggered IRQ1
- if ((m_icr & ICR_ET1) == ICR_ET1 && (data & INT_IRQ1_MASK) == INT_IRQ1_MASK)
+ if ((m_icr & ICR_ET1) == ICR_ET1 && ((data << 16) & INT_IRQ1_MASK) == INT_IRQ1_MASK)
{
m_isr &= ~INT_IRQ1_MASK;
}
// Clear edge-triggered IRQ2
- if ((m_icr & ICR_ET2) == ICR_ET2 && (data & INT_IRQ2_MASK) == INT_IRQ2_MASK)
+ if ((m_icr & ICR_ET2) == ICR_ET2 && ((data << 16) & INT_IRQ2_MASK) == INT_IRQ2_MASK)
{
m_isr &= ~INT_IRQ2_MASK;
}
// Clear edge-triggered IRQ3
- if ((m_icr & ICR_ET3) == ICR_ET3 && (data & INT_IRQ3_MASK) == INT_IRQ3_MASK)
+ if ((m_icr & ICR_ET3) == ICR_ET3 && ((data << 16) & INT_IRQ3_MASK) == INT_IRQ3_MASK)
{
m_isr &= ~INT_IRQ3_MASK;
}
// Clear edge-triggered IRQ6
- if ((m_icr & ICR_ET6) == ICR_ET6 && (data & INT_IRQ6_MASK) == INT_IRQ6_MASK)
+ if ((m_icr & ICR_ET6) == ICR_ET6 && ((data << 16) & INT_IRQ6_MASK) == INT_IRQ6_MASK)
{
m_isr &= ~INT_IRQ6_MASK;
}
// Clear edge-triggered IRQ7
- if ((data & INT_IRQ7_MASK) == INT_IRQ7_MASK)
+ if (((data << 16) & INT_IRQ7_MASK) == INT_IRQ7_MASK)
{
m_isr &= ~INT_IRQ7_MASK;
}
@@ -3081,12 +3087,38 @@ u16 mc68328_base_device::umisc_r() // 0x908
// LCD hardware - Shared and Standard MC68328
//-------------------------------------------------
+void mc68328_device::lcd_update_info()
+{
+ if (!m_lcd_update_pending)
+ {
+ return;
+ }
+ const u32 sysclk_divisor = VCO_DIVISORS[(m_pllcr & PLLCR_SYSCLK_SEL) >> PLLCR_SYSCLK_SHIFT];
+ attotime lcd_dma_duration = attotime::from_ticks(lcd_get_line_word_count() * sysclk_divisor, clock());
+ attotime lcd_scan_duration = lcd_get_line_rate();
+ attotime lcd_frame_duration = (lcd_scan_duration + lcd_dma_duration) * (m_lymax + 1);
+ LOGMASKED(LOG_LCD, "lxmax %d, lymax %d, divisor %d, lrra %02x, lpxcd %02x\n", m_lxmax, m_lymax + 1, sysclk_divisor, m_lpxcd + 1);
+
+ constexpr u8 BIT_WIDTHS[4] = { 1, 2, 4, 0xff };
+ if (!m_lcd_info_changed_cb.isnull())
+ {
+ m_lcd_info_changed_cb(lcd_frame_duration.as_hz(), lcd_get_width(), m_lymax + 1, BIT_WIDTHS[(m_lpicf & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT], BIT_WIDTHS[m_lpicf & LPICF_GS]);
+ }
+
+ m_lcd_update_pending = false;
+}
+
u16 mc68328_device::lcd_get_lxmax_mask()
{
constexpr u16 LXMAX_MASK = 0x03ff;
return LXMAX_MASK;
}
+int mc68328_device::lcd_get_width()
+{
+ return (m_lxmax & lcd_get_lxmax_mask()) + 1;
+}
+
u32 mc68328_device::lcd_get_line_word_count()
{
return m_lvpw != m_llbar ? (m_llbar + 1) : m_llbar;
@@ -3119,7 +3151,9 @@ void mc68328_base_device::fill_lcd_dma_buffer()
{
if (m_lcd_sysmem_ptr == m_lssa)
{
+ lcd_update_info();
m_out_flm_cb(BIT(m_lpolcf, LPOLCF_FLMPOL_BIT) ? 0 : 1);
+ m_lssa_end = m_lssa + ((m_lvpw * (m_lymax + 1)) << 1);
}
else
{
@@ -3138,9 +3172,7 @@ void mc68328_base_device::fill_lcd_dma_buffer()
}
m_lcd_sysmem_ptr += m_lvpw << 1;
-
- const u32 screen_max_addr = m_lssa + ((m_lvpw * (m_lymax + 1)) << 1);
- if (m_lcd_sysmem_ptr >= screen_max_addr)
+ if (m_lcd_sysmem_ptr >= m_lssa_end)
{
m_lcd_sysmem_ptr = m_lssa;
}
@@ -3245,7 +3277,7 @@ void mc68328_base_device::lvpw_w(u8 data) // 0xa05
{
LOGMASKED(LOG_LCD, "%s: lvpw_w: LVPW = %02x\n", machine().describe_context(), data);
m_lvpw = data;
- LOGMASKED(LOG_LCD, "%s: Virtual Page Width: %d words\n", machine().describe_context(), m_lvpw << 1);
+ LOGMASKED(LOG_LCD, "%s: Virtual Page Width: %d words\n", machine().describe_context(), m_lvpw);
}
u8 mc68328_base_device::lvpw_r() // 0xa05
@@ -3256,9 +3288,10 @@ u8 mc68328_base_device::lvpw_r() // 0xa05
void mc68328_base_device::lxmax_w(u16 data) // 0xa08
{
+ m_lcd_update_pending = m_lcd_update_pending || (m_lxmax != (data & lcd_get_lxmax_mask()));
LOGMASKED(LOG_LCD, "%s: lxmax_w: LXMAX = %04x\n", machine().describe_context(), data);
m_lxmax = data & lcd_get_lxmax_mask();
- LOGMASKED(LOG_LCD, "%s: Width: %d\n", machine().describe_context(), (data & 0x03ff) + 1);
+ LOGMASKED(LOG_LCD, "%s: Width: %d\n", machine().describe_context(), lcd_get_width());
}
u16 mc68328_base_device::lxmax_r() // 0xa08
@@ -3269,6 +3302,7 @@ u16 mc68328_base_device::lxmax_r() // 0xa08
void mc68328_base_device::lymax_w(u16 data) // 0xa0a
{
+ m_lcd_update_pending = m_lcd_update_pending || (m_lxmax != (data & LYMAX_MASK));
LOGMASKED(LOG_LCD, "%s: lymax_w: LYMAX = %04x\n", machine().describe_context(), data);
m_lymax = data & LYMAX_MASK;
LOGMASKED(LOG_LCD, "%s: Height: %d\n", machine().describe_context(), (data & 0x03ff) + 1);
@@ -3420,18 +3454,13 @@ void mc68328_device::lckcon_w(u8 data) // 0xa27
const u16 old = m_lckcon;
m_lckcon = data;
+ lcd_update_info();
if (BIT(old, LCKCON_LCDON_BIT) && !BIT(m_lckcon, LCKCON_LCDON_BIT))
{
m_lcd_scan->adjust(attotime::never);
}
else if (!BIT(old, LCKCON_LCDON_BIT) && BIT(m_lckcon, LCKCON_LCDON_BIT))
{
- const u32 sysclk_divisor = VCO_DIVISORS[(m_pllcr & PLLCR_SYSCLK_SEL) >> PLLCR_SYSCLK_SHIFT];
- attotime lcd_dma_duration = attotime::from_ticks(m_llbar, clock() / sysclk_divisor);
- attotime lcd_scan_duration = get_pixclk_rate() * (m_lxmax + 1);
- attotime lcd_frame_duration = (lcd_scan_duration + lcd_dma_duration) * (m_lymax + 1);
- m_lcd_info_changed_cb(lcd_frame_duration.as_hz(), m_lxmax + 1, m_lymax + 1);
-
m_lcd_scan->adjust(attotime::never);
m_lcd_sysmem_ptr = m_lssa;
fill_lcd_dma_buffer();
@@ -3517,24 +3546,52 @@ u16 mc68328_device::lgpmr_r() // 0xa32
// LCD hardware - EZ variant
//-------------------------------------------------
+void mc68ez328_device::lcd_update_info()
+{
+ if (!m_lcd_update_pending)
+ {
+ return;
+ }
+
+ const u32 sysclk_divisor = VCO_DIVISORS[(m_pllcr & PLLCR_SYSCLK_SEL) >> PLLCR_SYSCLK_SHIFT];
+ attotime lcd_dma_duration = attotime::from_ticks(lcd_get_line_word_count() * sysclk_divisor, clock());
+ attotime lcd_scan_duration = lcd_get_line_rate();
+ attotime lcd_frame_duration = (lcd_scan_duration + lcd_dma_duration) * (m_lymax + 1) * 2;
+
+ constexpr u8 BIT_WIDTHS[4] = { 1, 2, 4, 0xff };
+ if (!m_lcd_info_changed_cb.isnull())
+ {
+ m_lcd_info_changed_cb(lcd_frame_duration.as_hz(), lcd_get_width(), m_lymax + 1, BIT_WIDTHS[(m_lpicf & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT], BIT_WIDTHS[m_lpicf & LPICF_GS]);
+ }
+
+ m_lcd_update_pending = false;
+}
+
u16 mc68ez328_device::lcd_get_lxmax_mask()
{
constexpr u16 LXMAX_MASK = 0x03f0;
return LXMAX_MASK;
}
+int mc68ez328_device::lcd_get_width()
+{
+ return m_lxmax & lcd_get_lxmax_mask();
+}
+
u32 mc68ez328_device::lcd_get_line_word_count()
{
- const u32 pixels_per_word = 16 / lcd_get_panel_bit_size();
- return ((m_lxmax & lcd_get_lxmax_mask()) + 16) / pixels_per_word;
+ const u32 pixels_per_word = 16 / (1 << (m_lpicf & LPICF_GS));
+ const u32 data = (m_lxmax & lcd_get_lxmax_mask()) / pixels_per_word;
+ return data;
}
attotime mc68ez328_device::lcd_get_line_rate()
{
const u32 pixclk_divisor = VCO_DIVISORS[(m_pllcr & PLLCR_PIXCLK_SEL) >> PLLCR_PIXCLK_SHIFT];
const u32 pxcd = (m_lpxcd & LPXCD_MASK) + 1;
- const u32 lrra_factor = 6 + m_lrra + (m_lxmax & lcd_get_lxmax_mask()) + 16;
- return attotime::from_ticks(lrra_factor * pxcd * pixclk_divisor, clock());
+ const u32 lrra_factor = 6 + m_lrra + (m_lxmax & lcd_get_lxmax_mask()) * 4;
+ const u32 ticks = lrra_factor * pxcd * pixclk_divisor;
+ return attotime::from_ticks(ticks, clock());
}
u8 mc68ez328_device::lcd_get_panel_bit_size()
@@ -3556,6 +3613,7 @@ void mc68ez328_device::lpicf_w(u8 data) // 0xa20
LOGMASKED(LOG_LCD, "%s: lpicf_w: LPICF = %02x\n", machine().describe_context(), data);
LOGMASKED(LOG_LCD, "%s: Grayscale Mode: %d\n", machine().describe_context(), GS_NAMES[data & LPICF_GS]);
LOGMASKED(LOG_LCD, "%s: Bus Size: %s\n", machine().describe_context(), PBSIZ_NAMES[(data & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT]);
+ m_lcd_update_pending = m_lcd_update_pending || (m_lpicf != data);
m_lpicf = data;
}
@@ -3569,18 +3627,13 @@ void mc68ez328_device::lckcon_w(u8 data) // 0xa27
const u16 old = m_lckcon;
m_lckcon = data;
+ lcd_update_info();
if (BIT(old, LCKCON_LCDON_BIT) && !BIT(m_lckcon, LCKCON_LCDON_BIT))
{
m_lcd_scan->adjust(attotime::never);
}
else if (!BIT(old, LCKCON_LCDON_BIT) && BIT(m_lckcon, LCKCON_LCDON_BIT))
{
- const u32 sysclk_divisor = VCO_DIVISORS[(m_pllcr & PLLCR_SYSCLK_SEL) >> PLLCR_SYSCLK_SHIFT];
- attotime lcd_dma_duration = attotime::from_ticks(m_llbar, clock() / sysclk_divisor);
- attotime lcd_scan_duration = get_pixclk_rate() * (m_lxmax + 1);
- attotime lcd_frame_duration = (lcd_scan_duration + lcd_dma_duration) * (m_lymax + 1);
- m_lcd_info_changed_cb(lcd_frame_duration.as_hz(), m_lxmax + 1, m_lymax + 1);
-
m_lcd_scan->adjust(attotime::never);
m_lcd_sysmem_ptr = m_lssa;
fill_lcd_dma_buffer();
@@ -3590,6 +3643,7 @@ void mc68ez328_device::lckcon_w(u8 data) // 0xa27
void mc68ez328_device::lrra_w(u8 data) // 0xa29
{
LOGMASKED(LOG_LCD, "%s: lrra_w: LRRA = %02x\n", machine().describe_context(), data);
+ m_lcd_update_pending = m_lcd_update_pending || (m_lrra != data);
m_lrra = data;
}
diff --git a/src/devices/machine/mc68328.h b/src/devices/machine/mc68328.h
index 515c87549f1..dc1af423d61 100644
--- a/src/devices/machine/mc68328.h
+++ b/src/devices/machine/mc68328.h
@@ -93,7 +93,7 @@
class mc68328_base_device : public m68000_device
{
public:
- typedef device_delegate<void (double, int, int)> lcd_info_changed_delegate;
+ typedef device_delegate<void (double, int, int, u8, u8)> lcd_info_changed_delegate;
template <int Line> auto out_port_a() { return m_out_port_a_cb[Line].bind(); }
template <int Line> auto out_port_b() { return m_out_port_b_cb[Line].bind(); }
@@ -124,10 +124,10 @@ public:
DECLARE_WRITE_LINE_MEMBER(irq5_w);
- template <typename T>
- std::enable_if_t<lcd_info_changed_delegate::supports_callback<T>::value> set_lcd_info_changed(T &&callback, const char *name)
+ template <typename... T>
+ void set_lcd_info_changed(T &&... args)
{
- m_lcd_info_changed_cb.set(std::forward<T>(callback), name);
+ m_lcd_info_changed_cb.set(std::forward<T>(args)...);
}
protected:
@@ -346,11 +346,6 @@ protected:
LYMAX_MASK = 0x03ff,
- LGPMR_PAL2 = 0x0007,
- LGPMR_PAL3 = 0x0070,
- LGPMR_PAL0 = 0x0700,
- LGPMR_PAL1 = 0x7000,
-
RTCCTL_38_4_BIT = 5,
RTCCTL_ENABLE_BIT = 7,
RTCCTL_MASK = 0x00a0,
@@ -706,6 +701,7 @@ protected:
// $(FF)FFFA00
u32 m_lssa; // Screen Starting Address Register
+ u32 m_lssa_end; // Screen Starting Address Register, buffer end address (not memory-mapped)
u8 m_lvpw; // Virtual Page Width Register
u16 m_lxmax; // Screen Width Register
u16 m_lymax; // Screen Height Register
@@ -718,11 +714,9 @@ protected:
u8 m_lacdrc; // ACD (M) Rate Control Register
u8 m_lpxcd; // Pixel Clock Divider Register
u8 m_lckcon; // Clocking Control Register
- u8 m_llbar; // Last Buffer Address Register
- u8 m_lotcr; // Octet Terminal Count Register
u8 m_lposr; // Panning Offset Register
u8 m_lfrcm; // Frame Rate Control Modulation Register
- u16 m_lgpmr; // Gray Palette Mapping Register
+ bool m_lcd_update_pending;
// $(FF)FFFB00
u32 m_hmsr; // RTC Hours Minutes Seconds Register
@@ -751,7 +745,9 @@ protected:
template<int Timer> void update_gptimer_state();
template<int Timer> TIMER_CALLBACK_MEMBER(timer_tick);
+ virtual void lcd_update_info() = 0;
virtual u16 lcd_get_lxmax_mask() = 0;
+ virtual int lcd_get_width() = 0;
virtual u32 lcd_get_line_word_count() = 0;
virtual attotime lcd_get_line_rate() = 0;
virtual u8 lcd_get_panel_bit_size() = 0;
@@ -865,6 +861,11 @@ private:
PWMC_IRQEN = 0x4000,
PWMC_PWMIRQ = 0x8000,
+ LGPMR_PAL2 = 0x0007,
+ LGPMR_PAL3 = 0x0070,
+ LGPMR_PAL0 = 0x0700,
+ LGPMR_PAL1 = 0x7000,
+
WCTLR_WDRST = 0x0008,
WCTLR_LOCK = 0x0004,
WCTLR_FI = 0x0002,
@@ -1005,6 +1006,11 @@ private:
// $(FF)FFF700
u16 m_spisr; // SPIS Register
+ // $(FF)FFFA00
+ u8 m_llbar; // Last Buffer Address Register
+ u8 m_lotcr; // Octet Terminal Count Register
+ u16 m_lgpmr; // Gray Palette Mapping Register
+
void internal_map(address_map &map);
void cpu_space_map(address_map &map);
@@ -1020,7 +1026,9 @@ private:
virtual timer_regs &get_timer_regs(int timer) override;
virtual u32 get_timer_int(int timer) override;
+ virtual void lcd_update_info() override;
virtual u16 lcd_get_lxmax_mask() override;
+ virtual int lcd_get_width() override;
virtual u32 lcd_get_line_word_count() override;
virtual attotime lcd_get_line_rate() override;
virtual u8 lcd_get_panel_bit_size() override;
@@ -1225,7 +1233,9 @@ private:
virtual timer_regs &get_timer_regs(int timer) override;
virtual u32 get_timer_int(int timer) override;
+ virtual void lcd_update_info() override;
virtual u16 lcd_get_lxmax_mask() override;
+ virtual int lcd_get_width() override;
virtual u32 lcd_get_line_word_count() override;
virtual attotime lcd_get_line_rate() override;
virtual u8 lcd_get_panel_bit_size() override;
diff --git a/src/devices/video/mc68328lcd.cpp b/src/devices/video/mc68328lcd.cpp
new file mode 100644
index 00000000000..1864fcab22c
--- /dev/null
+++ b/src/devices/video/mc68328lcd.cpp
@@ -0,0 +1,149 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/******************************************************************************
+
+ Generic LCD emulation for use with MC68328/MC68EZ328 devices
+
+******************************************************************************/
+
+#include "emu.h"
+
+#include "mc68328lcd.h"
+
+#include "screen.h"
+
+DEFINE_DEVICE_TYPE(MC68328_LCD, mc68328_lcd_device, "mc68328_lcd", "MC68328-compatible LCD Controller")
+
+mc68328_lcd_device::mc68328_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, MC68328_LCD, tag, owner, clock)
+ , device_palette_interface(mconfig, *this)
+ , device_video_interface(mconfig, *this)
+{
+}
+
+void mc68328_lcd_device::device_start()
+{
+ save_item(NAME(m_lcd_first_line));
+ save_item(NAME(m_lcd_line_pulse));
+ save_item(NAME(m_lcd_shift_clk));
+ save_item(NAME(m_lcd_data));
+ save_item(NAME(m_lcd_scan_x));
+ save_item(NAME(m_lcd_scan_y));
+ save_item(NAME(m_bus_width));
+ save_item(NAME(m_bpp));
+
+ palette_init();
+}
+
+void mc68328_lcd_device::device_reset()
+{
+ m_lcd_first_line = true;
+ m_lcd_line_pulse = false;
+ m_lcd_shift_clk = false;
+ m_lcd_data = 0;
+ m_lcd_scan_x = 0;
+ m_lcd_scan_y = 0;
+ m_bus_width = 4;
+ m_bpp = 1;
+}
+
+void mc68328_lcd_device::palette_init()
+{
+ constexpr u8 LCD_OFF_R = 0xbd;
+ constexpr u8 LCD_OFF_G = 0xbd;
+ constexpr u8 LCD_OFF_B = 0xaa;
+ constexpr u8 LCD_ON_R = 0x40;
+ constexpr u8 LCD_ON_G = 0x40;
+ constexpr u8 LCD_ON_B = 0x40;
+ for (int i = 0; i < 16; i++)
+ {
+ const float lerp_factor = i / 15.f;
+ const u8 blend_r = (u8)(LCD_OFF_R * (1.f - lerp_factor) + LCD_ON_R * lerp_factor);
+ const u8 blend_g = (u8)(LCD_OFF_G * (1.f - lerp_factor) + LCD_ON_G * lerp_factor);
+ const u8 blend_b = (u8)(LCD_OFF_B * (1.f - lerp_factor) + LCD_ON_B * lerp_factor);
+ set_pen_color(i, blend_r, blend_g, blend_b);
+ }
+}
+
+DECLARE_WRITE_LINE_MEMBER(mc68328_lcd_device::flm_w)
+{
+ m_lcd_first_line = state;
+}
+
+DECLARE_WRITE_LINE_MEMBER(mc68328_lcd_device::llp_w)
+{
+ const int old = m_lcd_line_pulse;
+ m_lcd_line_pulse = state;
+ if (!state && old)
+ {
+ if (m_lcd_first_line)
+ {
+ m_lcd_scan_y = 0;
+ }
+ else
+ {
+ m_lcd_scan_y++;
+ }
+ m_lcd_scan_x = 0;
+ }
+}
+
+DECLARE_WRITE_LINE_MEMBER(mc68328_lcd_device::lsclk_w)
+{
+ const int old = m_lcd_shift_clk;
+ m_lcd_shift_clk = state;
+ if (state && !old)
+ {
+ for (u8 i = 0; i < m_bus_width && m_lcd_scan_x < m_lcd_bitmap.width() && m_lcd_scan_y < m_lcd_bitmap.height(); i += m_bpp)
+ {
+ u8 value = 0;
+ switch (m_bpp)
+ {
+ case 1:
+ value = BIT(m_lcd_data, (m_bus_width - 1) - i) * 15;
+ break;
+ case 2:
+ value = ((m_lcd_data >> ((m_bus_width - 2) - i)) & 3) * 5;
+ break;
+ case 4:
+ value = m_lcd_data & 15;
+ break;
+ }
+ if (m_lcd_scan_x < m_lcd_bitmap.width() && m_lcd_scan_y < m_lcd_bitmap.height())
+ {
+ m_lcd_bitmap.pix(m_lcd_scan_y, m_lcd_scan_x) = pen_color(value);
+ }
+ m_lcd_scan_x++;
+ }
+ }
+}
+
+void mc68328_lcd_device::ld_w(u8 data)
+{
+ m_lcd_data = data;
+}
+
+void mc68328_lcd_device::lcd_info_changed(double refresh_hz, int width, int height, u8 bus_width, u8 bpp)
+{
+ if (has_screen())
+ {
+ screen().set_refresh_hz(refresh_hz);
+ }
+ m_lcd_bitmap.resize(width, height);
+ m_bus_width = bus_width;
+ m_bpp = bpp;
+ m_lcd_scan_x = 0;
+ m_lcd_scan_y = 0;
+}
+
+void mc68328_lcd_device::video_update(bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ bitmap.fill(pen_color(0));
+ if (m_lcd_bitmap.valid())
+ {
+ u32 *src = &m_lcd_bitmap.pix(0);
+ u32 *dst = &bitmap.pix(0);
+ const int word_count = std::min(bitmap.width() * bitmap.height(), m_lcd_bitmap.width() * m_lcd_bitmap.height());
+ std::copy_n(src, word_count, dst);
+ }
+}
diff --git a/src/devices/video/mc68328lcd.h b/src/devices/video/mc68328lcd.h
new file mode 100644
index 00000000000..0954eaa6505
--- /dev/null
+++ b/src/devices/video/mc68328lcd.h
@@ -0,0 +1,53 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/******************************************************************************
+
+ Generic LCD emulation for use with MC68328/MC68EZ328 devices
+
+******************************************************************************/
+
+#ifndef MAME_VIDEO_MC68328LCD_H
+#define MAME_VIDEO_MC68328LCD_H
+
+#pragma once
+
+class mc68328_lcd_device : public device_t,
+ public device_palette_interface,
+ public device_video_interface
+{
+public:
+ mc68328_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ DECLARE_WRITE_LINE_MEMBER(flm_w);
+ DECLARE_WRITE_LINE_MEMBER(llp_w);
+ DECLARE_WRITE_LINE_MEMBER(lsclk_w);
+ void ld_w(u8 data);
+ void lcd_info_changed(double refresh_hz, int width, int height, u8 bus_width, u8 bpp);
+
+ void video_update(bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_palette_interface overrides
+ virtual uint32_t palette_entries() const noexcept override { return 16; }
+
+ void palette_init();
+
+ bitmap_rgb32 m_lcd_bitmap;
+ bool m_lcd_first_line;
+ bool m_lcd_line_pulse;
+ bool m_lcd_shift_clk;
+ u8 m_lcd_data;
+ u16 m_lcd_scan_x;
+ u16 m_lcd_scan_y;
+ u8 m_bus_width;
+ u8 m_bpp;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(MC68328_LCD, mc68328_lcd_device)
+
+#endif // MAME_VIDEO_MC68328LCD_H
diff --git a/src/mame/palm/palm.cpp b/src/mame/palm/palm.cpp
index be1036e5e74..9900b2372a0 100644
--- a/src/mame/palm/palm.cpp
+++ b/src/mame/palm/palm.cpp
@@ -16,9 +16,9 @@
#include "machine/mc68328.h"
#include "machine/ram.h"
#include "sound/dac.h"
+#include "video/mc68328lcd.h"
#include "video/sed1375.h"
-#include "emupal.h"
#include "screen.h"
#include "speaker.h"
@@ -50,12 +50,6 @@ protected:
offs_t dasm_override(std::ostream &stream, offs_t pc, const util::disasm_interface::data_buffer &opcodes, const util::disasm_interface::data_buffer &params);
- void flm_out(int state);
- void llp_out(int state);
- virtual void lsclk_out(int state);
- void ld_out(u8 data);
- void lcd_info_changed(double refresh_hz, int width, int height);
-
virtual int spi_from_hw();
required_device<mc68328_base_device> m_maincpu;
@@ -66,16 +60,6 @@ protected:
required_ioport m_io_penb;
u16 m_spim_data;
-
- bitmap_rgb32 m_lcd_bitmap;
- int m_lcd_first_line;
- int m_lcd_line_pulse;
- int m_lcd_shift_clk;
- u8 m_lcd_data;
- int m_lcd_scan_x;
- int m_lcd_scan_y;
-
- static const int EXTRA_ARTWORK_HEIGHT = 60;
};
class palm_state : public palm_base_state
@@ -83,7 +67,7 @@ class palm_state : public palm_base_state
public:
palm_state(const machine_config &mconfig, device_type type, const char *tag)
: palm_base_state(mconfig, type, tag)
- , m_palette(*this, "palette")
+ , m_lcdctrl(*this, "lcdctrl")
, m_io_portd(*this, "PORTD")
{ }
@@ -105,7 +89,6 @@ protected:
void mem_map(address_map &map);
u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
- void init_palette(palette_device &palette) const;
void check_pen_adc_read();
void adc_vcc_y_w(int state);
@@ -115,8 +98,6 @@ protected:
void adc_csn_w(int state);
int power_nmi_r();
- virtual void lsclk_out(int state) override;
-
enum : int
{
PORTF_Y_VCCN_BIT = 0,
@@ -126,7 +107,7 @@ protected:
PORTF_ADC_CSN_BIT = 7
};
- required_device<palette_device> m_palette;
+ required_device<mc68328_lcd_device> m_lcdctrl;
required_ioport m_io_portd;
u8 m_port_f_latch;
@@ -137,23 +118,23 @@ protected:
bool m_adc_gnd_y;
};
-class palmiiic_state : public palm_base_state
+class palmez_base_state : public palm_base_state
{
public:
- palmiiic_state(const machine_config &mconfig, device_type type, const char *tag)
+ DECLARE_INPUT_CHANGED_MEMBER(button_check);
+
+protected:
+ palmez_base_state(const machine_config &mconfig, device_type type, const char *tag, const u8 hardware_id)
: palm_base_state(mconfig, type, tag)
- , m_sed1375(*this, "lcdctrl")
, m_rows(*this, "ROW%u", 0u)
+ , m_hardware_id(hardware_id)
{ }
- void palmiiic(machine_config &config);
-
- DECLARE_INPUT_CHANGED_MEMBER(button_check);
-
-protected:
virtual void machine_start() override;
virtual void machine_reset() override;
+ void palmez_base(machine_config &config);
+
void mem_map(address_map &map);
void adc_enable_w(int state);
@@ -167,18 +148,55 @@ protected:
void spi_to_hw(int state);
virtual int spi_from_hw() override;
- required_device<sed1375_device> m_sed1375;
required_ioport_array<3> m_rows;
u8 m_key_row_mask;
u8 m_key_col_mask;
- bool m_port_d_hardware_id;
+
+ bool m_hardware_id_asserted;
+ const u8 m_hardware_id;
+
bool m_adc_enabled;
u8 m_adc_cmd_bit_count;
u8 m_adc_response_bit_count;
u8 m_adc_cmd;
};
+class palmiiic_state : public palmez_base_state
+{
+public:
+ palmiiic_state(const machine_config &mconfig, device_type type, const char *tag)
+ : palmez_base_state(mconfig, type, tag, 0x09)
+ , m_sed1375(*this, "lcdctrl")
+ { }
+
+ void palmiiic(machine_config &config);
+
+protected:
+ void mem_map(address_map &map);
+
+ required_device<sed1375_device> m_sed1375;
+};
+
+class palmm100_state : public palmez_base_state
+{
+public:
+ palmm100_state(const machine_config &mconfig, device_type type, const char *tag)
+ : palmez_base_state(mconfig, type, tag, 0x05)
+ , m_lcdctrl(*this, "lcdctrl")
+ { }
+
+ void palmm100(machine_config &config);
+
+protected:
+ template <int Line> int hardware_subid_r();
+
+ u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+ required_device<mc68328_lcd_device> m_lcdctrl;
+};
+
+
/***************************************************************************
MACHINE HARDWARE
***************************************************************************/
@@ -188,13 +206,6 @@ protected:
void palm_base_state::machine_start()
{
save_item(NAME(m_spim_data));
-
- save_item(NAME(m_lcd_first_line));
- save_item(NAME(m_lcd_line_pulse));
- save_item(NAME(m_lcd_shift_clk));
- save_item(NAME(m_lcd_data));
- save_item(NAME(m_lcd_scan_x));
- save_item(NAME(m_lcd_scan_y));
}
void palm_base_state::machine_reset()
@@ -205,13 +216,6 @@ void palm_base_state::machine_reset()
memcpy(m_ram->pointer(), bios, 0x20000);
m_spim_data = 0xffff;
-
- m_lcd_first_line = 1;
- m_lcd_line_pulse = 0;
- m_lcd_shift_clk = 0;
- m_lcd_data = 0;
- m_lcd_scan_x = 0;
- m_lcd_scan_y = 0;
}
INPUT_CHANGED_MEMBER(palm_base_state::pen_check)
@@ -227,6 +231,7 @@ int palm_base_state::spi_from_hw()
return out_state;
}
+
// First-generation Palm hardware ("IDT")
void palm_state::machine_start()
@@ -254,6 +259,12 @@ void palm_state::machine_reset()
m_adc_gnd_y = false;
}
+u32 palm_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ m_lcdctrl->video_update(bitmap, cliprect);
+ return 0;
+}
+
INPUT_CHANGED_MEMBER(palm_state::button_check)
{
const u8 button_state = m_io_portd->read();
@@ -310,9 +321,10 @@ int palm_state::power_nmi_r()
return 1;
}
-// Palm IIIc hardware ("Austin")
-void palmiiic_state::machine_start()
+// Basic 68EZ328-based Palm hardware
+
+void palmez_base_state::machine_start()
{
palm_base_state::machine_start();
address_space &space = m_maincpu->space(AS_PROGRAM);
@@ -320,28 +332,31 @@ void palmiiic_state::machine_start()
save_item(NAME(m_key_row_mask));
save_item(NAME(m_key_col_mask));
- save_item(NAME(m_port_d_hardware_id));
+
+ save_item(NAME(m_hardware_id_asserted));
+
save_item(NAME(m_adc_enabled));
save_item(NAME(m_adc_cmd_bit_count));
save_item(NAME(m_adc_response_bit_count));
save_item(NAME(m_adc_cmd));
}
-void palmiiic_state::machine_reset()
+void palmez_base_state::machine_reset()
{
palm_base_state::machine_reset();
m_key_row_mask = 0;
m_key_col_mask = 0;
- m_port_d_hardware_id = false;
+ m_hardware_id_asserted = false;
+
m_adc_enabled = false;
m_adc_cmd_bit_count = 8;
m_adc_response_bit_count = 0;
m_adc_cmd = 0;
}
-INPUT_CHANGED_MEMBER(palmiiic_state::button_check)
+INPUT_CHANGED_MEMBER(palmez_base_state::button_check)
{
const u8 button_state = m_rows[param]->read();
for (int bit = 0; bit < 4; bit++)
@@ -350,7 +365,7 @@ INPUT_CHANGED_MEMBER(palmiiic_state::button_check)
}
}
-void palmiiic_state::adc_enable_w(int state)
+void palmez_base_state::adc_enable_w(int state)
{
const bool was_enabled = m_adc_enabled;
m_adc_enabled = !state;
@@ -362,46 +377,39 @@ void palmiiic_state::adc_enable_w(int state)
}
template <int Line>
-void palmiiic_state::kbd_row_w(int state)
+void palmez_base_state::kbd_row_w(int state)
{
m_key_row_mask &= ~(1 << Line);
m_key_row_mask |= !state << Line;
}
template <int Line>
-void palmiiic_state::kbd_col_w(int state)
+void palmez_base_state::kbd_col_w(int state)
{
m_key_col_mask &= ~(1 << Line);
m_key_col_mask |= state << Line;
}
template <int Line>
-int palmiiic_state::kbd_scan_r()
+int palmez_base_state::kbd_scan_r()
{
- int state = 0;
- if (m_port_d_hardware_id)
+ if (m_hardware_id_asserted)
{
- state = BIT(~0x09, Line);
+ return BIT(~m_hardware_id, Line);
}
- else
+
+ int state = 0;
+ for (int i = 0; i < 3; i++)
{
- for (int i = 0; i < 3; i++)
+ if (BIT(m_key_row_mask, i))
{
- if (BIT(m_key_row_mask, i))
- {
- state |= BIT(m_rows[i]->read(), Line);
- }
+ state |= BIT(m_rows[i]->read(), Line);
}
}
return state;
}
-void palmiiic_state::hardware_id_req_w(int state)
-{
- m_port_d_hardware_id = !state;
-}
-
-void palmiiic_state::spi_to_hw(int state)
+void palmez_base_state::spi_to_hw(int state)
{
if (m_adc_enabled && m_adc_cmd_bit_count > 0)
{
@@ -411,7 +419,7 @@ void palmiiic_state::spi_to_hw(int state)
}
}
-int palmiiic_state::spi_from_hw()
+int palmez_base_state::spi_from_hw()
{
int state = palm_base_state::spi_from_hw();
if (m_adc_enabled && m_adc_cmd_bit_count == 0)
@@ -451,83 +459,25 @@ int palmiiic_state::spi_from_hw()
return state;
}
-
-/***************************************************************************
- LCD HARDWARE
-***************************************************************************/
-
-void palm_state::init_palette(palette_device &palette) const
+void palmez_base_state::hardware_id_req_w(int state)
{
- palette.set_pen_color(0, 0xbd, 0xbd, 0xaa);
- palette.set_pen_color(1, 0x40, 0x40, 0x40);
+ m_hardware_id_asserted = !state;
}
-void palm_base_state::flm_out(int state)
-{
- m_lcd_first_line = state;
-}
-void palm_base_state::llp_out(int state)
-{
- const int old = m_lcd_line_pulse;
- m_lcd_line_pulse = state;
- if (!state && old)
- {
- m_lcd_scan_x = 0;
- if (m_lcd_first_line)
- {
- m_lcd_scan_y = 0;
- }
- else
- {
- m_lcd_scan_y++;
- }
- }
-}
-
-void palm_base_state::lsclk_out(int state)
-{
- m_lcd_shift_clk = state;
-}
+// Palm m100 ("Brad") hardware
-void palm_state::lsclk_out(int state)
+u32 palmm100_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- const int old = m_lcd_shift_clk;
- palm_base_state::lsclk_out(state);
- if (state && !old)
- {
- for (u8 i = 0; i < 4; i++)
- {
- m_lcd_bitmap.pix(m_lcd_scan_y, m_lcd_scan_x) = m_palette->pen_color(BIT(m_lcd_data, 3 - i));
- m_lcd_scan_x++;
- }
- }
-}
-
-void palm_base_state::ld_out(u8 data)
-{
- m_lcd_data = data;
+ m_lcdctrl->video_update(bitmap, cliprect);
+ return 0;
}
-void palm_base_state::lcd_info_changed(double refresh_hz, int width, int height)
+template <int Line> int palmm100_state::hardware_subid_r()
{
- m_screen->set_refresh_hz(refresh_hz);
- m_screen->set_size(width, height + EXTRA_ARTWORK_HEIGHT);
- m_screen->set_visarea(0, width - 1, 0, (height + EXTRA_ARTWORK_HEIGHT) - 1);
- m_lcd_bitmap.resize(width, height);
+ return BIT(~0x00, Line);
}
-u32 palm_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
-{
- bitmap.fill(m_palette->pen_color(0));
- if (m_lcd_bitmap.valid())
- {
- u32 *src = &m_lcd_bitmap.pix(0);
- u32 *dst = &bitmap.pix(0);
- std::copy_n(src, m_lcd_bitmap.width() * m_lcd_bitmap.height(), dst);
- }
- return 0;
-}
/***************************************************************************
ADDRESS MAPS
@@ -538,10 +488,15 @@ void palm_state::mem_map(address_map &map)
map(0xc00000, 0xe07fff).rom().region("bios", 0);
}
-void palmiiic_state::mem_map(address_map &map)
+void palmez_base_state::mem_map(address_map &map)
{
map(0x00c00000, 0x00e07fff).rom().region("bios", 0);
map(0x10c00000, 0x10e07fff).rom().region("bios", 0);
+}
+
+void palmiiic_state::mem_map(address_map &map)
+{
+ palmez_base_state::mem_map(map);
map(0x1f000000, 0x1f01ffff).m(m_sed1375, FUNC(sed1375_device::map));
}
@@ -575,7 +530,7 @@ static INPUT_PORTS_START(palm)
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED)
INPUT_PORTS_END
-static INPUT_PORTS_START(palmez)
+static INPUT_PORTS_START(palmiiic)
PORT_INCLUDE(palm_base)
PORT_START("ROW0")
@@ -597,9 +552,29 @@ static INPUT_PORTS_START(palmez)
PORT_BIT(0xf8, IP_ACTIVE_HIGH, IPT_UNUSED)
INPUT_PORTS_END
+static INPUT_PORTS_START(palmm100)
+ PORT_INCLUDE(palm_base)
+
+ PORT_START("ROW0")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Button 1") PORT_CODE(KEYCODE_F) PORT_CHANGED_MEMBER(DEVICE_SELF, palmm100_state, button_check, 0)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Button 2") PORT_CODE(KEYCODE_G) PORT_CHANGED_MEMBER(DEVICE_SELF, palmm100_state, button_check, 0)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON4) PORT_NAME("Button 3") PORT_CODE(KEYCODE_J) PORT_CHANGED_MEMBER(DEVICE_SELF, palmm100_state, button_check, 0)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_BUTTON5) PORT_NAME("Button 4") PORT_CODE(KEYCODE_K) PORT_CHANGED_MEMBER(DEVICE_SELF, palmm100_state, button_check, 0)
+ PORT_BIT(0xf0, IP_ACTIVE_HIGH, IPT_UNUSED)
+
+ PORT_START("ROW1")
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON6) PORT_NAME("Down") PORT_CODE(KEYCODE_H) PORT_CHANGED_MEMBER(DEVICE_SELF, palmm100_state, button_check, 1)
+ PORT_BIT(0xfd, IP_ACTIVE_HIGH, IPT_UNUSED)
+
+ PORT_START("ROW2")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON7) PORT_NAME("Power") PORT_CODE(KEYCODE_D) PORT_CHANGED_MEMBER(DEVICE_SELF, palmm100_state, button_check, 2)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON8) PORT_NAME("Up") PORT_CODE(KEYCODE_Y) PORT_CHANGED_MEMBER(DEVICE_SELF, palmm100_state, button_check, 2)
+ PORT_BIT(0xfc, IP_ACTIVE_HIGH, IPT_UNUSED)
+INPUT_PORTS_END
+
/***************************************************************************
- MACHINE DRIVERS
+ MACHINE/DEVICE DRIVERS
***************************************************************************/
void palm_state::palm_base(machine_config &config)
@@ -626,24 +601,23 @@ void palm_state::palm_base(machine_config &config)
m_maincpu->in_port_d<6>().set_ioport(m_io_penb).bit(6);
m_maincpu->in_port_d<7>().set_ioport(m_io_penb).bit(7);
- //m_maincpu->in_port_f().set(FUNC(palm_state::port_f_in)); Port F latch
-
m_maincpu->out_pwm().set("dac", FUNC(dac_bit_interface::write));
m_maincpu->in_spim().set(FUNC(palm_state::spi_from_hw));
- m_maincpu->out_flm().set(FUNC(palm_state::flm_out));
- m_maincpu->out_llp().set(FUNC(palm_state::llp_out));
- m_maincpu->out_lsclk().set(FUNC(palm_state::lsclk_out));
- m_maincpu->out_ld().set(FUNC(palm_state::ld_out));
- m_maincpu->set_lcd_info_changed(FUNC(palm_state::lcd_info_changed));
+
+ m_maincpu->out_flm().set(m_lcdctrl, FUNC(mc68328_lcd_device::flm_w));
+ m_maincpu->out_llp().set(m_lcdctrl, FUNC(mc68328_lcd_device::llp_w));
+ m_maincpu->out_lsclk().set(m_lcdctrl, FUNC(mc68328_lcd_device::lsclk_w));
+ m_maincpu->out_ld().set(m_lcdctrl, FUNC(mc68328_lcd_device::ld_w));
+ m_maincpu->set_lcd_info_changed(m_lcdctrl, FUNC(mc68328_lcd_device::lcd_info_changed));
/* video hardware */
SCREEN(config, m_screen, SCREEN_TYPE_LCD);
m_screen->set_refresh_hz(60);
- m_screen->set_size(160, 160);
- m_screen->set_visarea(0, 159, 0, 159);
+ m_screen->set_size(160, 220);
+ m_screen->set_visarea(0, 160 - 1, 0, 220 - 1);
m_screen->set_screen_update(FUNC(palm_state::screen_update));
- PALETTE(config, m_palette, FUNC(palm_state::init_palette), 2);
+ MC68328_LCD(config, m_lcdctrl, 0);
/* audio hardware */
SPEAKER(config, "speaker").front_center();
@@ -685,11 +659,6 @@ void palmiiic_state::palmiiic(machine_config &config)
m_maincpu->out_pwm().set("dac", FUNC(dac_bit_interface::write));
m_maincpu->in_spim().set(FUNC(palmiiic_state::spi_from_hw));
m_maincpu->out_spim().set(FUNC(palmiiic_state::spi_to_hw));
- m_maincpu->out_flm().set(FUNC(palmiiic_state::flm_out));
- m_maincpu->out_llp().set(FUNC(palmiiic_state::llp_out));
- m_maincpu->out_lsclk().set(FUNC(palmiiic_state::lsclk_out));
- m_maincpu->out_ld().set(FUNC(palmiiic_state::ld_out));
- m_maincpu->set_lcd_info_changed(FUNC(palmiiic_state::lcd_info_changed));
/* internal ram */
RAM(config, RAM_TAG).set_default_size("8M");
@@ -708,6 +677,73 @@ void palmiiic_state::palmiiic(machine_config &config)
DAC_1BIT(config, "dac", 0).add_route(ALL_OUTPUTS, "speaker", 0.25);
}
+void palmm100_state::palmm100(machine_config &config)
+{
+ /* basic machine hardware */
+ MC68EZ328(config, m_maincpu, 32768*506); /* 16.580608 MHz */
+ m_maincpu->set_addrmap(AS_PROGRAM, &palmm100_state::mem_map);
+ m_maincpu->set_dasm_override(FUNC(palmm100_state::dasm_override));
+
+ m_maincpu->out_port_b<1>().set(FUNC(palmm100_state::kbd_row_w<0>));
+ m_maincpu->out_port_b<3>().set(FUNC(palmm100_state::kbd_row_w<1>));
+ m_maincpu->out_port_b<6>().set(FUNC(palmm100_state::kbd_row_w<2>));
+
+ m_maincpu->out_port_d<0>().set(FUNC(palmm100_state::kbd_col_w<0>));
+ m_maincpu->out_port_d<1>().set(FUNC(palmm100_state::kbd_col_w<1>));
+ m_maincpu->out_port_d<2>().set(FUNC(palmm100_state::kbd_col_w<2>));
+ m_maincpu->out_port_d<3>().set(FUNC(palmm100_state::kbd_col_w<3>));
+
+ m_maincpu->out_port_g<2>().set(FUNC(palmm100_state::hardware_id_req_w));
+ m_maincpu->out_port_g<5>().set(FUNC(palmm100_state::adc_enable_w));
+
+ m_maincpu->in_port_d<0>().set(FUNC(palmm100_state::kbd_scan_r<0>));
+ m_maincpu->in_port_d<1>().set(FUNC(palmm100_state::kbd_scan_r<1>));
+ m_maincpu->in_port_d<2>().set(FUNC(palmm100_state::kbd_scan_r<2>));
+ m_maincpu->in_port_d<3>().set(FUNC(palmm100_state::kbd_scan_r<3>));
+ m_maincpu->in_port_d<4>().set_constant(1); // Active-low, indicates hotsync/dock button press
+ m_maincpu->in_port_d<6>().set_constant(1); // Active-low, indicates external adapter installed
+ m_maincpu->in_port_d<7>().set_constant(1); // Active-low, indicates pending power failure
+
+ m_maincpu->in_port_e<0>().set(FUNC(palmm100_state::hardware_subid_r<0>));
+ m_maincpu->in_port_e<1>().set(FUNC(palmm100_state::hardware_subid_r<1>));
+ m_maincpu->in_port_e<2>().set(FUNC(palmm100_state::hardware_subid_r<2>));
+ m_maincpu->in_port_e<3>().set(FUNC(palmm100_state::hardware_subid_r<3>));
+ m_maincpu->in_port_e<4>().set(FUNC(palmm100_state::hardware_subid_r<4>));
+ m_maincpu->in_port_e<5>().set(FUNC(palmm100_state::hardware_subid_r<5>));
+ m_maincpu->in_port_e<6>().set(FUNC(palmm100_state::hardware_subid_r<6>));
+ m_maincpu->in_port_e<7>().set(FUNC(palmm100_state::hardware_subid_r<7>));
+
+ m_maincpu->in_port_f<0>().set_constant(1); // Active-high, indicates LCD is at full power
+ m_maincpu->in_port_f<6>().set_constant(1); // Active-high, indicates battery enabled
+ m_maincpu->in_port_f<7>().set_constant(1); // Active-low, determines sync port attachment
+
+ m_maincpu->out_pwm().set("dac", FUNC(dac_bit_interface::write));
+ m_maincpu->in_spim().set(FUNC(palmm100_state::spi_from_hw));
+ m_maincpu->out_spim().set(FUNC(palmm100_state::spi_to_hw));
+
+ m_maincpu->out_flm().set(m_lcdctrl, FUNC(mc68328_lcd_device::flm_w));
+ m_maincpu->out_llp().set(m_lcdctrl, FUNC(mc68328_lcd_device::llp_w));
+ m_maincpu->out_lsclk().set(m_lcdctrl, FUNC(mc68328_lcd_device::lsclk_w));
+ m_maincpu->out_ld().set(m_lcdctrl, FUNC(mc68328_lcd_device::ld_w));
+ m_maincpu->set_lcd_info_changed(m_lcdctrl, FUNC(mc68328_lcd_device::lcd_info_changed));
+
+ /* internal ram */
+ RAM(config, RAM_TAG).set_default_size("2M");
+
+ /* video hardware */
+ SCREEN(config, m_screen, SCREEN_TYPE_LCD);
+ m_screen->set_refresh_hz(60);
+ m_screen->set_size(160, 220);
+ m_screen->set_visarea(0, 160 - 1, 0, 220 - 1);
+ m_screen->set_screen_update(FUNC(palmm100_state::screen_update));
+
+ MC68328_LCD(config, m_lcdctrl, 0);
+
+ /* audio hardware */
+ SPEAKER(config, "speaker").front_center();
+ DAC_1BIT(config, "dac", 0).add_route(ALL_OUTPUTS, "speaker", 0.25);
+}
+
void palm_state::pilot1k(machine_config &config)
{
palm_base(config);
@@ -951,22 +987,22 @@ ROM_END
} // anonymous namespace
-// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
-COMP( 1996, pilot1k, 0, 0, pilot1k, palm, palm_state, empty_init, "U.S. Robotics", "Pilot 1000", MACHINE_SUPPORTS_SAVE )
-COMP( 1996, pilot5k, pilot1k, 0, pilot5k, palm, palm_state, empty_init, "U.S. Robotics", "Pilot 5000", MACHINE_SUPPORTS_SAVE )
-COMP( 1997, palmpers, pilot1k, 0, pilot5k, palm, palm_state, empty_init, "U.S. Robotics", "Palm Pilot Personal", MACHINE_SUPPORTS_SAVE )
-COMP( 1997, palmpro, pilot1k, 0, palmpro, palm, palm_state, empty_init, "U.S. Robotics", "Palm Pilot Pro", MACHINE_SUPPORTS_SAVE )
-COMP( 1998, palmiii, pilot1k, 0, palmiii, palm, palm_state, empty_init, "3Com", "Palm III", MACHINE_SUPPORTS_SAVE )
-COMP( 1998, palmiiic, pilot1k, 0, palmiiic, palmez, palmiiic_state, empty_init, "3Com", "Palm IIIc", MACHINE_SUPPORTS_SAVE )
-COMP( 2000, palmm100, pilot1k, 0, palmiii, palm, palm_state, empty_init, "3Com", "Palm m100", MACHINE_NOT_WORKING )
-COMP( 2000, palmm130, pilot1k, 0, palmiii, palm, palm_state, empty_init, "3Com", "Palm m130", MACHINE_NOT_WORKING )
-COMP( 2001, palmm505, pilot1k, 0, palmiii, palm, palm_state, empty_init, "3Com", "Palm m505", MACHINE_NOT_WORKING )
-COMP( 2001, palmm515, pilot1k, 0, palmiii, palm, palm_state, empty_init, "3Com", "Palm m515", MACHINE_NOT_WORKING )
-COMP( 1999, palmv, pilot1k, 0, palmv, palm, palm_state, empty_init, "3Com", "Palm V", MACHINE_NOT_WORKING )
-COMP( 1999, palmvx, pilot1k, 0, palmvx, palm, palm_state, empty_init, "3Com", "Palm Vx", MACHINE_NOT_WORKING )
-COMP( 2001, visor, pilot1k, 0, palmvx, palm, palm_state, empty_init, "Handspring", "Visor Edge", MACHINE_NOT_WORKING )
-COMP( 19??, spt1500, pilot1k, 0, palmvx, palm, palm_state, empty_init, "Symbol", "SPT 1500", MACHINE_NOT_WORKING )
-COMP( 19??, spt1700, pilot1k, 0, palmvx, palm, palm_state, empty_init, "Symbol", "SPT 1700", MACHINE_NOT_WORKING )
-COMP( 19??, spt1740, pilot1k, 0, palmvx, palm, palm_state, empty_init, "Symbol", "SPT 1740", MACHINE_NOT_WORKING )
+// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
+COMP( 1996, pilot1k, 0, 0, pilot1k, palm, palm_state, empty_init, "U.S. Robotics", "Pilot 1000", MACHINE_SUPPORTS_SAVE )
+COMP( 1996, pilot5k, pilot1k, 0, pilot5k, palm, palm_state, empty_init, "U.S. Robotics", "Pilot 5000", MACHINE_SUPPORTS_SAVE )
+COMP( 1997, palmpers, pilot1k, 0, pilot5k, palm, palm_state, empty_init, "U.S. Robotics", "Palm Pilot Personal", MACHINE_SUPPORTS_SAVE )
+COMP( 1997, palmpro, pilot1k, 0, palmpro, palm, palm_state, empty_init, "U.S. Robotics", "Palm Pilot Pro", MACHINE_SUPPORTS_SAVE )
+COMP( 1998, palmiii, pilot1k, 0, palmiii, palm, palm_state, empty_init, "3Com", "Palm III", MACHINE_SUPPORTS_SAVE )
+COMP( 1998, palmiiic, pilot1k, 0, palmiiic, palmiiic, palmiiic_state, empty_init, "3Com", "Palm IIIc", MACHINE_SUPPORTS_SAVE )
+COMP( 2000, palmm100, pilot1k, 0, palmm100, palmm100, palmm100_state, empty_init, "3Com", "Palm m100", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_GRAPHICS )
+COMP( 2000, palmm130, pilot1k, 0, palmiii, palm, palm_state, empty_init, "3Com", "Palm m130", MACHINE_NOT_WORKING )
+COMP( 2001, palmm505, pilot1k, 0, palmiii, palm, palm_state, empty_init, "3Com", "Palm m505", MACHINE_NOT_WORKING )
+COMP( 2001, palmm515, pilot1k, 0, palmiii, palm, palm_state, empty_init, "3Com", "Palm m515", MACHINE_NOT_WORKING )
+COMP( 1999, palmv, pilot1k, 0, palmv, palm, palm_state, empty_init, "3Com", "Palm V", MACHINE_NOT_WORKING )
+COMP( 1999, palmvx, pilot1k, 0, palmvx, palm, palm_state, empty_init, "3Com", "Palm Vx", MACHINE_NOT_WORKING )
+COMP( 2001, visor, pilot1k, 0, palmvx, palm, palm_state, empty_init, "Handspring", "Visor Edge", MACHINE_NOT_WORKING )
+COMP( 19??, spt1500, pilot1k, 0, palmvx, palm, palm_state, empty_init, "Symbol", "SPT 1500", MACHINE_NOT_WORKING )
+COMP( 19??, spt1700, pilot1k, 0, palmvx, palm, palm_state, empty_init, "Symbol", "SPT 1700", MACHINE_NOT_WORKING )
+COMP( 19??, spt1740, pilot1k, 0, palmvx, palm, palm_state, empty_init, "Symbol", "SPT 1740", MACHINE_NOT_WORKING )
#include "palm_dbg.ipp"
diff --git a/src/mame/vtech/iqunlim.cpp b/src/mame/vtech/iqunlim.cpp
index 26e1439a47c..92a4b7fc297 100644
--- a/src/mame/vtech/iqunlim.cpp
+++ b/src/mame/vtech/iqunlim.cpp
@@ -52,42 +52,116 @@ A4 = MAX232
*/
#include "emu.h"
-#include "screen.h"
-#include "cpu/m68000/m68000.h"
-#include "bus/generic/slot.h"
+#include "machine/mc68328.h"
+#include "machine/ram.h"
+#include "video/mc68328lcd.h"
+
#include "bus/generic/carts.h"
+#include "bus/generic/slot.h"
+
+#include "screen.h"
#include "softlist_dev.h"
+#define LOG_CARD_A_READ (1 << 1u)
+#define LOG_CARD_A_WRITE (1 << 2u)
+#define LOG_CARD_B_READ (1 << 3u)
+#define LOG_CARD_B_WRITE (1 << 4u)
+#define LOG_ALL (LOG_CARD_A_READ | LOG_CARD_A_WRITE | LOG_CARD_B_READ | LOG_CARD_B_WRITE)
+
+#define VERBOSE (LOG_ALL)
+#include "logmacro.h"
+
+namespace
+{
+
class iqunlim_state : public driver_device
{
public:
iqunlim_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
+ m_ram(*this, RAM_TAG),
+ m_lcdctrl(*this, "lcdctrl"),
+ m_screen(*this, "screen"),
m_cart(*this, "cartslot")
- { }
+ { }
void iqunlim(machine_config &config);
-private:
- required_device<cpu_device> m_maincpu;
- required_device<generic_slot_device> m_cart;
+protected:
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+
+ void mem_map(address_map &map);
+
+ uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+ void card4x_w(offs_t offset, uint16_t data, uint16_t mem_mask = 0xffff);
+ uint16_t card4x_r(offs_t offset, uint16_t mem_mask = 0xffff);
+ void card5x_w(offs_t offset, uint16_t data, uint16_t mem_mask = 0xffff);
+ uint16_t card5x_r(offs_t offset, uint16_t mem_mask = 0xffff);
DECLARE_DEVICE_IMAGE_LOAD_MEMBER(cart_load);
- virtual uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
- void iqunlim_mem(address_map &map);
+ required_device<mc68ez328_device> m_maincpu;
+ required_device<ram_device> m_ram;
+ required_device<mc68328_lcd_device> m_lcdctrl;
+ required_device<screen_device> m_screen;
+ required_device<generic_slot_device> m_cart;
};
+void iqunlim_state::machine_start()
+{
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ space.install_ram(0x00000000, m_ram->size() - 1, m_ram->pointer());
+}
+
+void iqunlim_state::machine_reset()
+{
+ // Copy ROM vectors into RAM
+ memcpy(m_ram->pointer(), memregion("maincpu")->base(), 0x8);
+}
+
+void iqunlim_state::mem_map(address_map &map)
+{
+ map(0x02000000, 0x023fffff).rom().region("maincpu", 0); // 68EZ328 /CSA0 pin selects System ROM after bootup
+ map(0x03000000, 0x0307ffff).ram(); // Region used by the internal flash memory
+ map(0x04000000, 0x04ffffff).rw(FUNC(iqunlim_state::card4x_r), FUNC(iqunlim_state::card4x_w)); // Region used by Card B
+ map(0x05000000, 0x05ffffff).rw(FUNC(iqunlim_state::card5x_r), FUNC(iqunlim_state::card5x_w)); // Region used by Card A
+}
+
uint32_t iqunlim_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
+ m_lcdctrl->video_update(bitmap, cliprect);
return 0;
}
-void iqunlim_state::iqunlim_mem(address_map &map)
+uint16_t iqunlim_state::card4x_r(offs_t offset, uint16_t mem_mask)
+{
+ uint16_t data = 0;
+ LOGMASKED(LOG_CARD_B_READ, "card4x_read[%08x]: %04x\n", offset << 1, data);
+ return data;
+}
+
+void iqunlim_state::card4x_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_CARD_B_WRITE, "card4x_write[%08x]: %04x\n", offset << 1, data);
+}
+
+uint16_t iqunlim_state::card5x_r(offs_t offset, uint16_t mem_mask)
+{
+ uint16_t data = 0xffff;
+ if (m_cart)
+ {
+ data = m_cart->read16_rom(offset, mem_mask);
+ }
+ LOGMASKED(LOG_CARD_A_READ, "card5x_read[%08x]: %04x\n", offset << 1, data);
+ return data;
+}
+
+void iqunlim_state::card5x_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
- map.unmap_value_high();
- map(0x000000, 0x1FFFFF).rom();
+ LOGMASKED(LOG_CARD_A_WRITE, "card5x_write[%08x]: %04x\n", offset << 1, data);
}
static INPUT_PORTS_START( iqunlim )
@@ -107,16 +181,25 @@ DEVICE_IMAGE_LOAD_MEMBER(iqunlim_state::cart_load)
void iqunlim_state::iqunlim(machine_config &config)
{
// Basic machine hardware
- M68000(config, m_maincpu, XTAL(32'000'000)/2); // DragonBall EZ (MC68EZ328, 68k core) (Is the xtal correct? This was from the other hardware)
- m_maincpu->set_addrmap(AS_PROGRAM, &iqunlim_state::iqunlim_mem);
+ MC68EZ328(config, m_maincpu, 32768*506);
+ m_maincpu->set_addrmap(AS_PROGRAM, &iqunlim_state::mem_map);
+
+ m_maincpu->out_flm().set(m_lcdctrl, FUNC(mc68328_lcd_device::flm_w));
+ m_maincpu->out_llp().set(m_lcdctrl, FUNC(mc68328_lcd_device::llp_w));
+ m_maincpu->out_lsclk().set(m_lcdctrl, FUNC(mc68328_lcd_device::lsclk_w));
+ m_maincpu->out_ld().set(m_lcdctrl, FUNC(mc68328_lcd_device::ld_w));
+ m_maincpu->set_lcd_info_changed(m_lcdctrl, FUNC(mc68328_lcd_device::lcd_info_changed));
+
+ RAM(config, RAM_TAG).set_default_size("2M");
// Video hardware
- screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
- screen.set_refresh_hz(50);
- screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); // Not accurate
- screen.set_size(512, 256);
- screen.set_visarea(0, 512-1, 0, 256-1);
- screen.set_screen_update(FUNC(iqunlim_state::screen_update));
+ SCREEN(config, m_screen, SCREEN_TYPE_LCD);
+ m_screen->set_refresh_hz(60);
+ m_screen->set_size(480, 260);
+ m_screen->set_visarea(0, 480 - 1, 0, 260 - 1);
+ m_screen->set_screen_update(FUNC(iqunlim_state::screen_update));
+
+ MC68328_LCD(config, m_lcdctrl, 0);
GENERIC_CARTSLOT(config, m_cart, generic_plain_slot, "iqunlim_cart");
m_cart->set_width(GENERIC_ROM16_WIDTH);
@@ -135,5 +218,7 @@ ROM_START( iqunlimgr )
ROM_LOAD16_WORD_SWAP( "27-06126-007.bin", 0x000000, 0x400000, CRC(2e99cfef) SHA1(790869ffcf7fd666def8ff57fce0691062b3cec5) )
ROM_END
+} // anonymous namespace
+
COMP( 1995, iqunlim, 0, 0, iqunlim, iqunlim, iqunlim_state, empty_init, "VTech / Integrated Systems Inc.", "IQ Unlimited", MACHINE_IS_SKELETON) // COPYRIGHT 1995 INTERGRATED SYSTEMS, INC.
COMP( 1995, iqunlimgr, iqunlim, 0, iqunlim, iqunlim, iqunlim_state, empty_init, "VTech / Integrated Systems Inc.", "IQ Unlimited (Germany)", MACHINE_IS_SKELETON) // COPYRIGHT 1995 INTERGRATED SYSTEMS, INC.