diff options
Diffstat (limited to 'src/devices/video/mc68328lcd.cpp')
-rw-r--r-- | src/devices/video/mc68328lcd.cpp | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/src/devices/video/mc68328lcd.cpp b/src/devices/video/mc68328lcd.cpp new file mode 100644 index 00000000000..ad0b721c41e --- /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); + } +} + +void mc68328_lcd_device::flm_w(int state) +{ + m_lcd_first_line = state; +} + +void mc68328_lcd_device::llp_w(int state) +{ + 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; + } +} + +void mc68328_lcd_device::lsclk_w(int state) +{ + 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); + } +} |