diff options
Diffstat (limited to 'src/devices/video/lc7985.cpp')
-rw-r--r-- | src/devices/video/lc7985.cpp | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/src/devices/video/lc7985.cpp b/src/devices/video/lc7985.cpp new file mode 100644 index 00000000000..ef01cbb6a2c --- /dev/null +++ b/src/devices/video/lc7985.cpp @@ -0,0 +1,302 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + Sanyo LC7985NA/LC7985ND LCD controller + +***************************************************************************/ + +#include "emu.h" +#include "lc7985.h" + +DEFINE_DEVICE_TYPE(LC7985, lc7985_device, "lc7985", "Sanyo LC7985NA/LC7985ND LCD controller") + + +ROM_START( lc7985 ) + ROM_REGION( 0x1000, "cgrom", 0 ) + ROM_LOAD( "lc7985.bin", 0x0000, 0x1000, BAD_DUMP CRC(fdc64160) SHA1(8e6b54f8fb7c4c15aab2e65dd1a44729b97423b1)) // from page 12 of the LC7985D datasheet +ROM_END + +lc7985_device::lc7985_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, LC7985, tag, owner, clock), + m_cgrom_region(*this, DEVICE_SELF) +{ +} + +const tiny_rom_entry *lc7985_device::device_rom_region() const +{ + return ROM_NAME(lc7985); +} + +void lc7985_device::device_start() +{ + m_cgrom = m_cgrom_region.found() ? m_cgrom_region : memregion("cgrom")->base(); + m_busy_timer = timer_alloc(FUNC(lc7985_device::clear_busy_flag), this); + + save_item(NAME(m_ddram)); + save_item(NAME(m_cgram)); + save_item(NAME(m_busy_flag)); + save_item(NAME(m_ddac)); + save_item(NAME(m_cgac)); + save_item(NAME(m_shift)); + save_item(NAME(m_access_ddram)); + save_item(NAME(m_function)); + save_item(NAME(m_cds)); +} + +void lc7985_device::device_reset() +{ + memset(m_ddram, 0x20, sizeof(m_ddram)); // filled with SPACE char + memset(m_cgram, 0, sizeof(m_cgram)); + m_ddac = 0x00; + m_cgac = 0x00; + m_shift = 0x00; + m_access_ddram = false; + m_function = 0x00; + m_cds = 0x00; + m_display = 0x00; + m_entry = 0x02; + + busy(attotime::from_msec(10)); +} + +void lc7985_device::busy(attotime time) +{ + m_busy_flag = true; + m_busy_timer->adjust(time); +} + +TIMER_CALLBACK_MEMBER(lc7985_device::clear_busy_flag) +{ + m_busy_flag = false; +} + +void lc7985_device::inc_ddac() +{ + if(m_function & 0x08) { // 2 lines + if(m_ddac == 39) + m_ddac = 64; + else if(m_ddac == 64+39) + m_ddac = 0; + else + m_ddac++; + } else { + if(m_ddac == 79) + m_ddac = 0; + else + m_ddac++; + } +} + +void lc7985_device::dec_ddac() +{ + if(m_function & 0x08) { // 2 lines + if(m_ddac == 64) + m_ddac = 39; + else if(m_ddac == 0) + m_ddac = 64+39; + else + m_ddac--; + } else { + if(m_ddac == 0) + m_ddac = 79; + else + m_ddac--; + } +} + +void lc7985_device::shift_left() +{ + if(m_shift == 79) + m_shift = 0; + else + m_shift++; +} + +void lc7985_device::shift_right() +{ + if(m_shift == 0) + m_shift = 79; + else + m_shift--; +} + +void lc7985_device::ir_w(u8 data) +{ + if(m_busy_flag) + return; + + if(data & 0x80) { + // Set DDRAM address + m_ddac = data & 0x7f; + m_access_ddram = true; + busy(attotime::from_usec(40)); + + } else if(data & 0x40) { + // Set CGRAM address + m_cgac = data & 0x3f; + m_access_ddram = false; + busy(attotime::from_usec(40)); + + } else if(data & 0x20) { + // Set Function + m_function = data; + busy(attotime::from_usec(40)); + + } else if(data & 0x10) { + // Cursor/Display Shift + m_access_ddram = true; + switch((data >> 2) & 3) { + case 0: dec_ddac(); break; + case 1: inc_ddac(); break; + case 2: shift_left(); break; + case 3: shift_right(); break; + } + + busy(attotime::from_usec(40)); + + } else if(data & 0x08) { + // Display On/Off + m_display = data; + busy(attotime::from_usec(40)); + + } else if(data & 0x04) { + // Set Entry Mode + m_entry = data; + busy(attotime::from_usec(40)); + + } else if(data & 0x02) { + // Cursor home + m_ddac = 0; + m_shift = 0; + m_access_ddram = true; + busy(attotime::from_usec(16400)); + + } else if(data & 0x01) { + // Display clear + memset(m_ddram, 0x20, sizeof(m_ddram)); + m_ddac = 0x00; + m_entry |= 0x02; + busy(attotime::from_usec(16400)); + } +} + +u8 lc7985_device::status_r() +{ + return (m_access_ddram ? m_ddac : m_cgac) | (m_busy_flag ? 0x80 : 0x00); +} + +void lc7985_device::dr_w(u8 data) +{ + if(m_access_ddram) { + m_ddram[(m_function & 0x08) && m_ddac >= 64 ? m_ddac - (64-40) : m_ddac] = data; + switch(m_entry & 0x03) { + case 0: dec_ddac(); break; + case 1: dec_ddac(); shift_right(); break; + case 2: inc_ddac(); break; + case 3: inc_ddac(); shift_left(); break; + } + + } else { + m_cgram[m_cgac] = data; + if(m_entry & 0x02) + m_cgac = (m_cgac + 1) & 0x3f; + else + m_cgac = (m_cgac - 1) & 0x3f; + } +} + +u8 lc7985_device::dr_r() +{ + u8 res; + if(m_access_ddram) { + res = m_ddram[(m_function & 0x08) && m_ddac >= 64 ? m_ddac - (64-40) : m_ddac]; + if(m_entry & 0x02) + inc_ddac(); + else + dec_ddac(); + + } else { + res = m_cgram[m_cgac]; + if(m_entry & 0x02) + m_cgac = (m_cgac + 1) & 0x3f; + else + m_cgac = (m_cgac - 1) & 0x3f; + } + return res; +} + +const u8 *lc7985_device::render() +{ + memset(m_render_buffer, 0, sizeof(m_render_buffer)); + if(!(m_display & 0x04)) + return m_render_buffer; + + if(m_function & 0x08) { + for(int y = 0; y != 2; y++) { + for(int x = 0; x != 40; x ++) { + u8 c = m_ddram[((x + 80 - m_shift) % 40) + 40*y]; + const u8 *src = c < 32 ? m_cgram + 8*(c & 7) : m_cgrom + 16 * c; + u8 *dest = m_render_buffer + 8 * y + 16 * x; + for(int z = 0; z != 8; z ++) + *dest++ = *src++ & 0x1f; + } + } + if(m_display & 0x03) { + int cx = ((m_ddac & 0x3f) + 80 - m_shift) % 80; + u8 *dest = m_render_buffer + (m_ddac >= 0x40 ? 8 : 0) + 16*cx; + if(m_display & 0x02) + dest[7] = 0x1f; + if(m_display & 0x01) { + bool on = int(machine().time().as_double() / 0.409) & 1; + if(on) + for(int z = 0; z != 8; z ++) + *dest++ = 0x1f; + } + } + + } else if(m_function & 0x04) { + for(int x = 0; x != 80; x ++) { + u8 c = m_ddram[(x + 80 - m_shift) % 80]; + const u8 *src = c < 32 ? m_cgram + 8*(c & 6) : m_cgrom + 16 * c; + u8 *dest = m_render_buffer + 16 * x; + for(int z = 0; z != 11; z ++) + *dest++ = *src++ & 0x1f; + } + if(m_display & 0x03) { + int cx = (m_ddac + 80 - m_shift) % 80; + u8 *dest = m_render_buffer + 16*cx; + if(m_display & 0x02) + dest[10] = 0x1f; + if(m_display & 0x01) { + bool on = int(machine().time().as_double() / 0.409) & 1; + if(on) + for(int z = 0; z != 11; z ++) + *dest++ = 0x1f; + } + } + + } else { + for(int x = 0; x != 80; x ++) { + u8 c = m_ddram[(x + 80 - m_shift) % 80]; + const u8 *src = c < 32 ? m_cgram + 8*(c & 7) : m_cgrom + 16 * c; + u8 *dest = m_render_buffer + 16 * x; + for(int z = 0; z != 8; z ++) + *dest++ = *src++ & 0x1f; + } + if(m_display & 0x03) { + int cx = (m_ddac + 80 - m_shift) % 80; + u8 *dest = m_render_buffer + 16*cx; + if(m_display & 0x02) + dest[7] = 0x1f; + if(m_display & 0x01) { + bool on = int(machine().time().as_double() / 0.409) & 1; + if(on) + for(int z = 0; z != 8; z ++) + *dest++ = 0x1f; + } + } + } + return m_render_buffer; +} + |