// license:BSD-3-Clause // copyright-holders:Sandro Ronco /*************************************************************************** VTech Laser PC4 LCD controller emulation ***************************************************************************/ #include "emu.h" #include "includes/pc4.h" void pc4_state::set_busy_flag(uint16_t usec) { m_busy_flag = 1; m_busy_timer->adjust( attotime::from_usec( usec ) ); } uint32_t pc4_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { bitmap.fill(0, cliprect); if (m_display_on) for (int l=0; l<4; l++) for (int i=0; i<40; i++) { uint16_t char_pos = l*40 + i; for (int y=0; y<8; y++) for (int x=0; x<5; x++) if (m_ddram[char_pos] <= 0x10) { //draw CGRAM characters bitmap.pix16(l*9 + y, i*6 + x) = BIT(m_cgram[(m_ddram[char_pos]&0x07)*8+y], 4-x); } else { //draw CGROM characters bitmap.pix16(l*9 + y, i*6 + x) = BIT(m_region_charset->base()[m_ddram[char_pos]*8+y], 4-x); } // if is the correct position draw cursor and blink if (char_pos == m_cursor_pos) { //draw the cursor if (m_cursor_on) for (int x=0; x<5; x++) bitmap.pix16(l*9 + 7, i * 6 + x) = 1; if (!m_blink && m_blink_on) for (int y=0; y<7; y++) for (int x=0; x<5; x++) bitmap.pix16(l*9 + y, i * 6 + x) = 1; } } return 0; } void pc4_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { switch(id) { case BUSY_TIMER: m_busy_flag = 0; break; case BLINKING_TIMER: m_blink = !m_blink; break; } } WRITE8_MEMBER(pc4_state::lcd_control_w) { if (BIT(data, 7)) { m_ac_mode = 0; m_cursor_pos = m_ac = data & 0x7f; set_busy_flag(37); } else if (BIT(data, 6)) { m_ac_mode = 1; m_ac = data & 0x3f; set_busy_flag(37); } else if (BIT(data, 5)) { m_cursor_on = BIT(data, 3); set_busy_flag(37); } else if (BIT(data, 4)) { uint8_t direct = (BIT(data, 2)) ? +1 : -1; if (BIT(data, 3)) m_disp_shift += direct; else { m_ac += direct; m_cursor_pos += direct; } set_busy_flag(37); } else if (BIT(data, 3)) { m_display_on = BIT(data, 2); //m_cursor_on = BIT(data, 1); m_blink_on = BIT(data, 0); set_busy_flag(37); } else if (BIT(data, 2)) { m_direction = (BIT(data, 1)) ? +1 : -1; m_shift_on = BIT(data, 0); set_busy_flag(37); } else if (BIT(data, 1)) { m_ac = 0; m_cursor_pos = 0; m_ac_mode = 0; m_direction = 1; m_disp_shift = 0; set_busy_flag(520); } else if (BIT(data, 0)) { m_ac = 0; m_cursor_pos = 0; m_ac_mode = 0; m_direction = 1; m_disp_shift = 0; memset(m_ddram, 0x20, sizeof(m_ddram)); set_busy_flag(520); } } READ8_MEMBER(pc4_state::lcd_control_r) { return (m_busy_flag<<7) | (m_ac & 0x7f); } void pc4_state::update_ac(void) { int new_ac = m_ac + m_direction; m_ac = (new_ac < 0) ? 0 : ((new_ac >= 0xa0) ? 0xa0 : new_ac); if (m_ac_mode == 0) { m_cursor_pos = m_ac; // display is shifted only after a write if (m_shift_on && m_data_bus_flag == 1) m_disp_shift += m_direction; } m_data_bus_flag = 0; } WRITE8_MEMBER( pc4_state::lcd_offset_w ) { m_cursor_pos = m_ac = (data%0xa0); } WRITE8_MEMBER(pc4_state::lcd_data_w) { if (m_ac_mode == 0) m_ddram[m_ac] = data; else m_cgram[m_ac] = data; update_ac(); set_busy_flag(41); } READ8_MEMBER(pc4_state::lcd_data_r) { uint8_t data; if (m_ac_mode == 0) data = m_ddram[m_ac]; else data = m_cgram[m_ac]; m_data_bus_flag = 2; update_ac(); set_busy_flag(41); return data; }