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]
This commit is contained in:
MooglyGuy 2022-12-21 17:15:56 +01:00 committed by GitHub
parent 14c680e940
commit 3178442049
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 638 additions and 239 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
: palm_base_state(mconfig, type, tag)
, m_sed1375(*this, "lcdctrl")
, m_rows(*this, "ROW%u", 0u)
{ }
void palmiiic(machine_config &config);
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_rows(*this, "ROW%u", 0u)
, m_hardware_id(hardware_id)
{ }
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,84 +459,26 @@ 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++;
}
}
}
// Palm m100 ("Brad") hardware
void palm_base_state::lsclk_out(int state)
u32 palmm100_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
m_lcd_shift_clk = state;
}
void palm_state::lsclk_out(int state)
{
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;
}
void palm_base_state::lcd_info_changed(double refresh_hz, int width, int height)
{
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);
}
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);
}
m_lcdctrl->video_update(bitmap, cliprect);
return 0;
}
template <int Line> int palmm100_state::hardware_subid_r()
{
return BIT(~0x00, Line);
}
/***************************************************************************
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"

View File

@ -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)
{
map.unmap_value_high();
map(0x000000, 0x1FFFFF).rom();
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)
{
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.