From 31784420490007231546cfa07150d069fb339f34 Mon Sep 17 00:00:00 2001 From: MooglyGuy Date: Wed, 21 Dec 2022 17:15:56 +0100 Subject: 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] --- scripts/src/video.lua | 12 ++ src/devices/machine/mc68328.cpp | 114 +++++++++--- src/devices/machine/mc68328.h | 34 ++-- src/devices/video/mc68328lcd.cpp | 149 +++++++++++++++ src/devices/video/mc68328lcd.h | 53 ++++++ src/mame/palm/palm.cpp | 382 +++++++++++++++++++++------------------ src/mame/vtech/iqunlim.cpp | 125 +++++++++++-- 7 files changed, 634 insertions(+), 235 deletions(-) create mode 100644 src/devices/video/mc68328lcd.cpp create mode 100644 src/devices/video/mc68328lcd.h 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 @@ -689,6 +689,18 @@ if (VIDEOS["MB_VCU"]~=null) then } 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(1024 / 8); // 1024px wide, up to 8 pixels per word + m_lcd_line_buffer = std::make_unique(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 lcd_info_changed_delegate; + typedef device_delegate lcd_info_changed_delegate; template auto out_port_a() { return m_out_port_a_cb[Line].bind(); } template auto out_port_b() { return m_out_port_b_cb[Line].bind(); } @@ -124,10 +124,10 @@ public: DECLARE_WRITE_LINE_MEMBER(irq5_w); - template - std::enable_if_t::value> set_lcd_info_changed(T &&callback, const char *name) + template + void set_lcd_info_changed(T &&... args) { - m_lcd_info_changed_cb.set(std::forward(callback), name); + m_lcd_info_changed_cb.set(std::forward(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 void update_gptimer_state(); template 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 ¶ms); - 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 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 m_palette; + required_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 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 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 hardware_subid_r(); + + u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + required_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 -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 -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 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 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 m_maincpu; - required_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 m_maincpu; + required_device m_ram; + required_device m_lcdctrl; + required_device m_screen; + required_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. -- cgit v1.2.3